python-on-a-chip online compiler

Dependencies:   mbed TSI

/media/uploads/va009039/p14p-f446re.png

more info: python-on-a-chip

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Sat Mar 02 11:54:20 2013 +0000
Child:
1:28afb064a41c
Commit message:
first commit

Changed in this revision

mbed.bld Show annotated file Show diff for this revision Revisions of this file
platform/mbed/main.cpp Show annotated file Show diff for this revision Revisions of this file
platform/mbed/main_img.cpp Show annotated file Show diff for this revision Revisions of this file
platform/mbed/main_nat.cpp Show annotated file Show diff for this revision Revisions of this file
platform/mbed/plat.cpp Show annotated file Show diff for this revision Revisions of this file
platform/mbed/plat.h Show annotated file Show diff for this revision Revisions of this file
platform/mbed/pmfeatures.h Show annotated file Show diff for this revision Revisions of this file
platform/mbed/pmstdlib_img.cpp Show annotated file Show diff for this revision Revisions of this file
platform/mbed/pmstdlib_nat.cpp Show annotated file Show diff for this revision Revisions of this file
vm/bytearray.c Show annotated file Show diff for this revision Revisions of this file
vm/bytearray.h Show annotated file Show diff for this revision Revisions of this file
vm/class.c Show annotated file Show diff for this revision Revisions of this file
vm/class.h Show annotated file Show diff for this revision Revisions of this file
vm/codeobj.c Show annotated file Show diff for this revision Revisions of this file
vm/codeobj.h Show annotated file Show diff for this revision Revisions of this file
vm/dict.c Show annotated file Show diff for this revision Revisions of this file
vm/dict.h Show annotated file Show diff for this revision Revisions of this file
vm/float.c Show annotated file Show diff for this revision Revisions of this file
vm/float.h Show annotated file Show diff for this revision Revisions of this file
vm/frame.c Show annotated file Show diff for this revision Revisions of this file
vm/frame.h Show annotated file Show diff for this revision Revisions of this file
vm/func.c Show annotated file Show diff for this revision Revisions of this file
vm/func.h Show annotated file Show diff for this revision Revisions of this file
vm/global.c Show annotated file Show diff for this revision Revisions of this file
vm/global.h Show annotated file Show diff for this revision Revisions of this file
vm/heap.c Show annotated file Show diff for this revision Revisions of this file
vm/heap.h Show annotated file Show diff for this revision Revisions of this file
vm/img.c Show annotated file Show diff for this revision Revisions of this file
vm/img.h Show annotated file Show diff for this revision Revisions of this file
vm/int.c Show annotated file Show diff for this revision Revisions of this file
vm/int.h Show annotated file Show diff for this revision Revisions of this file
vm/interp.c Show annotated file Show diff for this revision Revisions of this file
vm/interp.h Show annotated file Show diff for this revision Revisions of this file
vm/list.c Show annotated file Show diff for this revision Revisions of this file
vm/list.h Show annotated file Show diff for this revision Revisions of this file
vm/mem.c Show annotated file Show diff for this revision Revisions of this file
vm/mem.h Show annotated file Show diff for this revision Revisions of this file
vm/module.c Show annotated file Show diff for this revision Revisions of this file
vm/module.h Show annotated file Show diff for this revision Revisions of this file
vm/obj.c Show annotated file Show diff for this revision Revisions of this file
vm/obj.h Show annotated file Show diff for this revision Revisions of this file
vm/plat_interface.h Show annotated file Show diff for this revision Revisions of this file
vm/pm.c Show annotated file Show diff for this revision Revisions of this file
vm/pm.h Show annotated file Show diff for this revision Revisions of this file
vm/pmEmptyPlatformDefs.h Show annotated file Show diff for this revision Revisions of this file
vm/pmFeatureDependencies.h Show annotated file Show diff for this revision Revisions of this file
vm/seglist.c Show annotated file Show diff for this revision Revisions of this file
vm/seglist.h Show annotated file Show diff for this revision Revisions of this file
vm/seq.c Show annotated file Show diff for this revision Revisions of this file
vm/seq.h Show annotated file Show diff for this revision Revisions of this file
vm/sli.c Show annotated file Show diff for this revision Revisions of this file
vm/sli.h Show annotated file Show diff for this revision Revisions of this file
vm/strobj.c Show annotated file Show diff for this revision Revisions of this file
vm/strobj.h Show annotated file Show diff for this revision Revisions of this file
vm/thread.c Show annotated file Show diff for this revision Revisions of this file
vm/thread.h Show annotated file Show diff for this revision Revisions of this file
vm/tuple.c Show annotated file Show diff for this revision Revisions of this file
vm/tuple.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/3d0ef94e36ec
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/mbed/main.cpp	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,41 @@
+/*
+# This file is Copyright 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.
+*/
+
+
+#include "pm.h"
+
+
+#ifdef __cplusplus
+extern
+#endif
+
+#define HEAP_SIZE 0x7000
+
+unsigned char const 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);
+
+    /* Run the sample program */
+    retval = pm_run((uint8_t *)"main");
+
+    return (int)retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/mbed/main_img.cpp	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,274 @@
+/**
+ * PyMite library image file.
+ *
+ * Automatically created from:
+ *     main.py
+ *    mbed.py
+ *    img-list-terminator
+ * by pmImgCreator.py on
+ * Sat Mar 02 20:27:03 2013.
+ * 
+ * Byte count: 1916
+ * 
+ * Selected memspace type: RAM
+ * 
+ * DO NOT EDIT THIS FILE.
+ * ANY CHANGES WILL BE LOST.
+ */
+
+/* Place the image into RAM */
+#ifdef __cplusplus
+extern
+#endif
+unsigned char const
+usrlib_img[32368] =
+{
+
+
+/* main.py */
+    0x0A, 0x5D, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 
+    0x0D, 0x00, 0x04, 0x03, 0x03, 0x03, 0x00, 0x69, 
+    0x70, 0x6D, 0x03, 0x07, 0x00, 0x67, 0x6C, 0x6F, 
+    0x62, 0x61, 0x6C, 0x73, 0x03, 0x04, 0x00, 0x6D, 
+    0x61, 0x69, 0x6E, 0x03, 0x02, 0x00, 0x0C, 0x01, 
+    0x03, 0x08, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x02, 0x01, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 
+    0x64, 0x01, 0x00, 0x6B, 0x00, 0x00, 0x5A, 0x00, 
+    0x00, 0x65, 0x00, 0x00, 0x69, 0x00, 0x00, 0x65, 
+    0x01, 0x00, 0x83, 0x00, 0x00, 0x83, 0x01, 0x00, 
+    0x01, 0x64, 0x01, 0x00, 0x53, 
+
+/* mbed.py */
+    0x0A, 0x1E, 0x07, 0x00, 0x40, 0x03, 0x00, 0x00, 
+    0x1D, 0x00, 0x04, 0x0C, 0x03, 0x07, 0x00, 0x5F, 
+    0x5F, 0x64, 0x6F, 0x63, 0x5F, 0x5F, 0x03, 0x06, 
+    0x00, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x03, 
+    0x08, 0x00, 0x41, 0x6E, 0x61, 0x6C, 0x6F, 0x67, 
+    0x49, 0x6E, 0x03, 0x09, 0x00, 0x41, 0x6E, 0x61, 
+    0x6C, 0x6F, 0x67, 0x4F, 0x75, 0x74, 0x03, 0x09, 
+    0x00, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6C, 
+    0x49, 0x6E, 0x03, 0x0A, 0x00, 0x44, 0x69, 0x67, 
+    0x69, 0x74, 0x61, 0x6C, 0x4F, 0x75, 0x74, 0x03, 
+    0x06, 0x00, 0x50, 0x77, 0x6D, 0x4F, 0x75, 0x74, 
+    0x03, 0x06, 0x00, 0x53, 0x65, 0x72, 0x69, 0x61, 
+    0x6C, 0x03, 0x03, 0x00, 0x53, 0x50, 0x49, 0x03, 
+    0x03, 0x00, 0x49, 0x32, 0x43, 0x03, 0x07, 0x00, 
+    0x73, 0x65, 0x74, 0x5F, 0x6C, 0x65, 0x64, 0x03, 
+    0x04, 0x00, 0x6D, 0x62, 0x65, 0x64, 0x03, 0x14, 
+    0x00, 0x06, 0x03, 0x16, 0x6F, 0x16, 0xA9, 0x16, 
+    0x4E, 0x16, 0x76, 0x16, 0xFF, 0x00, 0x3F, 0x16, 
+    0xA3, 0x16, 0xB7, 0x16, 0xB8, 0x03, 0x08, 0x00, 
+    0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 0x79, 0x00, 
+    0x04, 0x13, 0x00, 0x03, 0x08, 0x00, 0x41, 0x6E, 
+    0x61, 0x6C, 0x6F, 0x67, 0x49, 0x6E, 0x0A, 0x93, 
+    0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x20, 0x00, 
+    0x04, 0x06, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 
+    0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 
+    0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 
+    0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, 
+    0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x08, 0x00, 
+    0x72, 0x65, 0x61, 0x64, 0x5F, 0x75, 0x31, 0x36, 
+    0x03, 0x04, 0x00, 0x72, 0x65, 0x61, 0x64, 0x03, 
+    0x08, 0x00, 0x41, 0x6E, 0x61, 0x6C, 0x6F, 0x67, 
+    0x49, 0x6E, 0x03, 0x06, 0x00, 0x06, 0x02, 0x09, 
+    0x2B, 0x09, 0x21, 0x03, 0x08, 0x00, 0x6D, 0x62, 
+    0x65, 0x64, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x03, 
+    0x0B, 0x02, 0xFF, 0xFF, 0x0B, 0x01, 0xFE, 0xFF, 
+    0x0B, 0x01, 0xFD, 0xFF, 0x04, 0x00, 0x65, 0x00, 
+    0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x02, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x52, 
+    0x53, 0x03, 0x09, 0x00, 0x41, 0x6E, 0x61, 0x6C, 
+    0x6F, 0x67, 0x4F, 0x75, 0x74, 0x0A, 0xAC, 0x00, 
+    0x00, 0x42, 0x01, 0x00, 0x00, 0x8F, 0x00, 0x04, 
+    0x07, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 
+    0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 
+    0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 
+    0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, 0x6E, 
+    0x69, 0x74, 0x5F, 0x5F, 0x03, 0x09, 0x00, 0x77, 
+    0x72, 0x69, 0x74, 0x65, 0x5F, 0x75, 0x31, 0x36, 
+    0x03, 0x05, 0x00, 0x77, 0x72, 0x69, 0x74, 0x65, 
+    0x03, 0x04, 0x00, 0x72, 0x65, 0x61, 0x64, 0x03, 
+    0x09, 0x00, 0x41, 0x6E, 0x61, 0x6C, 0x6F, 0x67, 
+    0x4F, 0x75, 0x74, 0x03, 0x08, 0x00, 0x06, 0x02, 
+    0x09, 0x2C, 0x09, 0x28, 0x09, 0x32, 0x03, 0x08, 
+    0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x04, 0x0B, 0x02, 0xFC, 0xFF, 0x0B, 
+    0x02, 0xFB, 0xFF, 0x0B, 0x02, 0xFA, 0xFF, 0x0B, 
+    0x01, 0xF9, 0xFF, 0x04, 0x00, 0x65, 0x00, 0x00, 
+    0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x02, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, 0x03, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, 0x52, 
+    0x53, 0x03, 0x09, 0x00, 0x44, 0x69, 0x67, 0x69, 
+    0x74, 0x61, 0x6C, 0x49, 0x6E, 0x0A, 0x7A, 0x00, 
+    0x00, 0x42, 0x01, 0x00, 0x00, 0x38, 0x01, 0x04, 
+    0x05, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 
+    0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 
+    0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 
+    0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, 0x6E, 
+    0x69, 0x74, 0x5F, 0x5F, 0x03, 0x04, 0x00, 0x72, 
+    0x65, 0x61, 0x64, 0x03, 0x09, 0x00, 0x44, 0x69, 
+    0x67, 0x69, 0x74, 0x61, 0x6C, 0x49, 0x6E, 0x03, 
+    0x04, 0x00, 0x06, 0x02, 0x09, 0x2B, 0x03, 0x08, 
+    0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x02, 0x0B, 0x02, 0xF8, 0xFF, 0x0B, 
+    0x01, 0xF7, 0xFF, 0x04, 0x00, 0x65, 0x00, 0x00, 
+    0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x03, 0x00, 0x52, 0x53, 0x03, 
+    0x0A, 0x00, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 
+    0x6C, 0x4F, 0x75, 0x74, 0x0A, 0x92, 0x00, 0x00, 
+    0x42, 0x01, 0x00, 0x00, 0x86, 0x01, 0x04, 0x06, 
+    0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, 
+    0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 0x5F, 
+    0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 0x5F, 
+    0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, 0x6E, 0x69, 
+    0x74, 0x5F, 0x5F, 0x03, 0x04, 0x00, 0x72, 0x65, 
+    0x61, 0x64, 0x03, 0x05, 0x00, 0x77, 0x72, 0x69, 
+    0x74, 0x65, 0x03, 0x0A, 0x00, 0x44, 0x69, 0x67, 
+    0x69, 0x74, 0x61, 0x6C, 0x4F, 0x75, 0x74, 0x03, 
+    0x06, 0x00, 0x06, 0x02, 0x09, 0x2B, 0x09, 0x21, 
+    0x03, 0x08, 0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x03, 0x0B, 0x02, 0xF6, 
+    0xFF, 0x0B, 0x01, 0xF5, 0xFF, 0x0B, 0x02, 0xF4, 
+    0xFF, 0x04, 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 
+    0x00, 0x64, 0x00, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x02, 0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x03, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x04, 0x00, 0x52, 0x53, 0x03, 0x06, 
+    0x00, 0x50, 0x77, 0x6D, 0x4F, 0x75, 0x74, 0x0A, 
+    0x1F, 0x01, 0x00, 0x42, 0x01, 0x00, 0x00, 0xFC, 
+    0x01, 0x04, 0x0B, 0x03, 0x08, 0x00, 0x5F, 0x5F, 
+    0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 
+    0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 
+    0x65, 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 
+    0x69, 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x04, 
+    0x00, 0x72, 0x65, 0x61, 0x64, 0x03, 0x06, 0x00, 
+    0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x03, 0x09, 
+    0x00, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x5F, 
+    0x6D, 0x73, 0x03, 0x09, 0x00, 0x70, 0x65, 0x72, 
+    0x69, 0x6F, 0x64, 0x5F, 0x75, 0x73, 0x03, 0x0A, 
+    0x00, 0x70, 0x75, 0x6C, 0x73, 0x65, 0x77, 0x69, 
+    0x64, 0x74, 0x68, 0x03, 0x0D, 0x00, 0x70, 0x75, 
+    0x73, 0x6C, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 
+    0x5F, 0x6D, 0x73, 0x03, 0x0D, 0x00, 0x70, 0x75, 
+    0x6C, 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 
+    0x5F, 0x75, 0x73, 0x03, 0x06, 0x00, 0x50, 0x77, 
+    0x6D, 0x4F, 0x75, 0x74, 0x03, 0x10, 0x00, 0x06, 
+    0x02, 0x09, 0x2B, 0x09, 0x21, 0x09, 0x28, 0x09, 
+    0x28, 0x09, 0x28, 0x09, 0x28, 0x09, 0x28, 0x03, 
+    0x08, 0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 
+    0x79, 0x00, 0x04, 0x08, 0x0B, 0x02, 0xF3, 0xFF, 
+    0x0B, 0x01, 0xF2, 0xFF, 0x0B, 0x02, 0xF1, 0xFF, 
+    0x0B, 0x02, 0xF0, 0xFF, 0x0B, 0x02, 0xEF, 0xFF, 
+    0x0B, 0x02, 0xEE, 0xFF, 0x0B, 0x02, 0xED, 0xFF, 
+    0x0B, 0x02, 0xEC, 0xFF, 0x04, 0x00, 0x65, 0x00, 
+    0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x02, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, 
+    0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, 
+    0x64, 0x04, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x06, 
+    0x00, 0x64, 0x05, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x07, 0x00, 0x64, 0x06, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x08, 0x00, 0x64, 0x07, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x09, 0x00, 0x52, 0x53, 0x03, 0x06, 
+    0x00, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x0A, 
+    0xA3, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x3A, 
+    0x03, 0x04, 0x07, 0x03, 0x08, 0x00, 0x5F, 0x5F, 
+    0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 
+    0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 
+    0x65, 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 
+    0x69, 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x04, 
+    0x00, 0x70, 0x75, 0x74, 0x63, 0x03, 0x04, 0x00, 
+    0x70, 0x75, 0x74, 0x73, 0x03, 0x04, 0x00, 0x67, 
+    0x65, 0x74, 0x63, 0x03, 0x06, 0x00, 0x53, 0x65, 
+    0x72, 0x69, 0x61, 0x6C, 0x03, 0x08, 0x00, 0x06, 
+    0x02, 0x09, 0x30, 0x09, 0x28, 0x09, 0x28, 0x03, 
+    0x08, 0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 
+    0x79, 0x00, 0x04, 0x04, 0x0B, 0x03, 0xEB, 0xFF, 
+    0x0B, 0x02, 0xEA, 0xFF, 0x0B, 0x02, 0xE9, 0xFF, 
+    0x0B, 0x01, 0xE8, 0xFF, 0x04, 0x00, 0x65, 0x00, 
+    0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x02, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, 
+    0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, 
+    0x52, 0x53, 0x03, 0x03, 0x00, 0x53, 0x50, 0x49, 
+    0x0A, 0xB0, 0x00, 0x00, 0x42, 0x02, 0x00, 0x00, 
+    0xDD, 0x03, 0x04, 0x07, 0x03, 0x08, 0x00, 0x5F, 
+    0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 
+    0x0A, 0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 
+    0x6C, 0x65, 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 
+    0x5F, 0x69, 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 
+    0x06, 0x00, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 
+    0x03, 0x09, 0x00, 0x66, 0x72, 0x65, 0x71, 0x75, 
+    0x65, 0x6E, 0x63, 0x79, 0x03, 0x05, 0x00, 0x77, 
+    0x72, 0x69, 0x74, 0x65, 0x03, 0x03, 0x00, 0x53, 
+    0x50, 0x49, 0x03, 0x08, 0x00, 0x06, 0x02, 0x09, 
+    0x34, 0x0C, 0x30, 0x09, 0x28, 0x03, 0x08, 0x00, 
+    0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 0x79, 0x00, 
+    0x04, 0x05, 0x0B, 0x04, 0xE7, 0xFF, 0x01, 0x00, 
+    0x00, 0x00, 0x00, 0x0B, 0x03, 0xE6, 0xFF, 0x0B, 
+    0x02, 0xE5, 0xFF, 0x0B, 0x02, 0xE4, 0xFF, 0x04, 
+    0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 
+    0x00, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 
+    0x64, 0x01, 0x00, 0x64, 0x02, 0x00, 0x84, 0x01, 
+    0x00, 0x5A, 0x03, 0x00, 0x64, 0x03, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, 0x04, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, 0x52, 0x53, 
+    0x03, 0x03, 0x00, 0x49, 0x32, 0x43, 0x0A, 0xA6, 
+    0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x94, 0x04, 
+    0x04, 0x07, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 
+    0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 
+    0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 
+    0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, 
+    0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x09, 0x00, 
+    0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6E, 0x63, 
+    0x79, 0x03, 0x04, 0x00, 0x72, 0x65, 0x61, 0x64, 
+    0x03, 0x05, 0x00, 0x77, 0x72, 0x69, 0x74, 0x65, 
+    0x03, 0x03, 0x00, 0x49, 0x32, 0x43, 0x03, 0x08, 
+    0x00, 0x06, 0x02, 0x09, 0x30, 0x09, 0x28, 0x09, 
+    0x30, 0x03, 0x08, 0x00, 0x6D, 0x62, 0x65, 0x64, 
+    0x2E, 0x70, 0x79, 0x00, 0x04, 0x04, 0x0B, 0x03, 
+    0xE3, 0xFF, 0x0B, 0x02, 0xE2, 0xFF, 0x0B, 0x04, 
+    0xE1, 0xFF, 0x0B, 0x04, 0xE0, 0xFF, 0x04, 0x00, 
+    0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 
+    0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 
+    0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 
+    0x00, 0x64, 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x05, 0x00, 0x52, 0x53, 0x0B, 0x02, 0xDF, 0xFF, 
+    0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x5A, 0x00, 
+    0x00, 0x64, 0x01, 0x00, 0x65, 0x01, 0x00, 0x66, 
+    0x01, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 
+    0x83, 0x00, 0x00, 0x59, 0x5A, 0x02, 0x00, 0x64, 
+    0x03, 0x00, 0x65, 0x01, 0x00, 0x66, 0x01, 0x00, 
+    0x64, 0x04, 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 
+    0x00, 0x59, 0x5A, 0x03, 0x00, 0x64, 0x05, 0x00, 
+    0x65, 0x01, 0x00, 0x66, 0x01, 0x00, 0x64, 0x06, 
+    0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 
+    0x5A, 0x04, 0x00, 0x64, 0x07, 0x00, 0x65, 0x01, 
+    0x00, 0x66, 0x01, 0x00, 0x64, 0x08, 0x00, 0x84, 
+    0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x05, 
+    0x00, 0x64, 0x09, 0x00, 0x65, 0x01, 0x00, 0x66, 
+    0x01, 0x00, 0x64, 0x0A, 0x00, 0x84, 0x00, 0x00, 
+    0x83, 0x00, 0x00, 0x59, 0x5A, 0x06, 0x00, 0x64, 
+    0x0B, 0x00, 0x65, 0x01, 0x00, 0x66, 0x01, 0x00, 
+    0x64, 0x0C, 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 
+    0x00, 0x59, 0x5A, 0x07, 0x00, 0x64, 0x0D, 0x00, 
+    0x65, 0x01, 0x00, 0x66, 0x01, 0x00, 0x64, 0x0E, 
+    0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 
+    0x5A, 0x08, 0x00, 0x64, 0x0F, 0x00, 0x65, 0x01, 
+    0x00, 0x66, 0x01, 0x00, 0x64, 0x10, 0x00, 0x84, 
+    0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x09, 
+    0x00, 0x64, 0x11, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x0A, 0x00, 0x64, 0x12, 0x00, 0x53, 
+
+/* img-list-terminator */
+    0xFF, 
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/mbed/main_nat.cpp	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,1472 @@
+#undef __FILE_ID__
+#define __FILE_ID__ 0x0A
+/**
+ * PyMite usr native function file
+ *
+ * automatically created by pmImgCreator.py
+ * on Sat Mar 02 20:27:03 2013
+ *
+ * DO NOT EDIT THIS FILE.
+ * ANY CHANGES WILL BE LOST.
+ *
+ * @file    main_nat.cpp
+ */
+
+#define __IN_LIBNATIVE_C__
+#include "pm.h"
+
+/* From: mbed.py */
+#include "mbed.h"
+
+static DigitalOut led1(LED1);
+static DigitalOut led2(LED2);
+static DigitalOut led3(LED3);
+static DigitalOut led4(LED4);
+
+/* PinName lookup table.  Converts pin number to PinName. */
+static PinName const pinNumToName[] = {
+    NC, LED1, LED2, LED3, LED4, p5, p6, p7, p8, p9,
+    p10, p11, p12, p13, p14, p15, p16, p17, p18, p19,
+    p20, p21, p22, p23, p24, p25, p26, p27, p28, p29,
+    p30
+};
+
+PmReturn_t
+nat_placeholder_func(pPmFrame_t *ppframe)
+{
+
+    /*
+     * Use placeholder because an index 
+     * value of zero denotes the stdlib.
+     * This function should not be called.
+     */
+    PmReturn_t retval;
+    PM_RAISE(retval, PM_RET_EX_SYS);
+    return retval;
+
+}
+
+PmReturn_t
+nat_01_mbed___init__(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        AnalogIn *adc;
+        uint8_t objid;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Instantiate the C++ object */
+        adc = new AnalogIn(pinNumToName[((pPmInt_t)pn)->val]);
+
+        /* Save the pointer to adc as an inaccessible attribute */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = int_new((uint32_t)adc, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pn, &objid);
+        retval = dict_setItem(pattrs, PM_NONE, pn);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_02_mbed_read_u16(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        AnalogIn *adc;
+        int32_t n;
+
+        /* If wrong number of args, throw type exception */
+        if (NATIVE_GET_NUM_ARGS() != 1)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        adc = (AnalogIn *)((pPmInt_t)pn)->val;
+
+        /* Return input value on the stack */
+        n = adc->read_u16();
+        retval = int_new(n, &pn);
+        NATIVE_SET_TOS(pn);
+
+        return retval;
+        
+}
+
+PmReturn_t
+nat_03_mbed_read(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        AnalogIn *adc;
+        float n;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 1)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        adc = (AnalogIn *)((pPmInt_t)pn)->val;
+
+        /* Return input value on the stack */
+        n = adc->read();
+        retval = float_new(n, &pn);
+        NATIVE_SET_TOS(pn);
+
+        return retval;
+        
+}
+
+PmReturn_t
+nat_04_mbed___init__(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        AnalogOut *dac;
+        uint8_t objid;
+
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Instantiate the object */
+        dac = new AnalogOut(pinNumToName[((pPmInt_t)pn)->val]);
+
+        /* Save the pointer to adc as an inaccessible attribute */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = int_new((uint32_t)dac, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pn, &objid);
+        retval = dict_setItem(pattrs, PM_NONE, pn);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_05_mbed_write_u16(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        AnalogOut *dac;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        dac = (AnalogOut *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        dac->write_u16(((pPmInt_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_06_mbed_write(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        AnalogOut *dac;
+        float n;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_FLT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        dac = (AnalogOut *)((pPmInt_t)pn)->val;
+
+        /* Saturate and write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        n = ((pPmFloat_t)pn)->val;
+        if (n < 0.0)
+        {
+            n = 0.0;
+        }
+        else if (n > 1.0)
+        {
+            n = 1.0;
+        }
+        dac->write(n);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_07_mbed_read(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        AnalogOut *dac;
+        float n;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 1)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        dac = (AnalogOut *)((pPmInt_t)pn)->val;
+
+        /* Return output value on the stack */
+        n = dac->read();
+        retval = float_new(n, &pn);
+        NATIVE_SET_TOS(pn);
+
+        return retval;
+        
+}
+
+PmReturn_t
+nat_08_mbed___init__(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        DigitalIn *din;
+        uint8_t objid;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Instantiate the C++ object */
+        din = new DigitalIn(pinNumToName[((pPmInt_t)pn)->val]);
+
+        /* Save the pointer to adc as an inaccessible attribute */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = int_new((uint32_t)din, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pn, &objid);
+        retval = dict_setItem(pattrs, PM_NONE, pn);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_09_mbed_read(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        DigitalIn *din;
+        int32_t n;
+
+        /* If wrong number of args, throw type exception */
+        if (NATIVE_GET_NUM_ARGS() != 1)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        din = (DigitalIn *)((pPmInt_t)pn)->val;
+
+        /* Return input value on the stack */
+        n = din->read();
+        retval = int_new(n, &pn);
+        NATIVE_SET_TOS(pn);
+
+        return retval;
+        
+}
+
+PmReturn_t
+nat_10_mbed___init__(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        DigitalOut *dout;
+        uint8_t objid;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Instantiate the C++ object */
+        dout = new DigitalOut(pinNumToName[((pPmInt_t)pn)->val]);
+
+        /* Save the pointer to adc as an inaccessible attribute */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = int_new((uint32_t)dout, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pn, &objid);
+        retval = dict_setItem(pattrs, PM_NONE, pn);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_11_mbed_read(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        DigitalOut *dout;
+        int32_t n;
+
+        /* If wrong number of args, throw type exception */
+        if (NATIVE_GET_NUM_ARGS() != 1)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        dout = (DigitalOut *)((pPmInt_t)pn)->val;
+
+        /* Return input value on the stack */
+        n = dout->read();
+        retval = int_new(n, &pn);
+        NATIVE_SET_TOS(pn);
+
+        return retval;
+        
+}
+
+PmReturn_t
+nat_12_mbed_write(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        DigitalOut *dout;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        dout = (DigitalOut *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        dout->write(((pPmInt_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_13_mbed___init__(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        PwmOut *pwm;
+        uint8_t objid;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Instantiate the C++ object */
+        pwm = new PwmOut(pinNumToName[((pPmInt_t)pn)->val]);
+
+        /* Save the pointer to pwm as an inaccessible attribute */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = int_new((uint32_t)pwm, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pn, &objid);
+        retval = dict_setItem(pattrs, PM_NONE, pn);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_14_mbed_read(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        DigitalOut *dout;
+        int32_t n;
+
+        /* If wrong number of args, throw type exception */
+        if (NATIVE_GET_NUM_ARGS() != 1)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        dout = (DigitalOut *)((pPmInt_t)pn)->val;
+
+        /* Return input value on the stack */
+        n = dout->read();
+        retval = int_new(n, &pn);
+        NATIVE_SET_TOS(pn);
+
+        return retval;
+        
+}
+
+PmReturn_t
+nat_15_mbed_period(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        PwmOut *pwm;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        pwm = (PwmOut *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        pwm->period(((pPmInt_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_16_mbed_period_ms(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        PwmOut *pwm;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        pwm = (PwmOut *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        pwm->period_ms(((pPmInt_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_17_mbed_period_us(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        PwmOut *pwm;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        pwm = (PwmOut *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        pwm->period_us(((pPmInt_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_18_mbed_pulsewidth(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        PwmOut *pwm;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        pwm = (PwmOut *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        pwm->pulsewidth(((pPmInt_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_19_mbed_puslewidth_ms(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        PwmOut *pwm;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        pwm = (PwmOut *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        pwm->pulsewidth_ms(((pPmInt_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_20_mbed_pulsewidth_us(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        PwmOut *pwm;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        pwm = (PwmOut *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        pwm->pulsewidth_us(((pPmInt_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_21_mbed___init__(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t ptx;
+        pPmObj_t prx;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        Serial *ser;
+        uint8_t objid;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 3)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        ptx = NATIVE_GET_LOCAL(1);
+        prx = NATIVE_GET_LOCAL(2);
+        if ((OBJ_GET_TYPE(ptx) != OBJ_TYPE_INT)
+            || (OBJ_GET_TYPE(prx) != OBJ_TYPE_INT))
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Instantiate the C++ object */
+        ser = new Serial(pinNumToName[((pPmInt_t)ptx)->val],
+                         pinNumToName[((pPmInt_t)prx)->val]);
+
+        /* Save the pointer to ser as an inaccessible attribute */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = int_new((uint32_t)ser, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pn, &objid);
+        retval = dict_setItem(pattrs, PM_NONE, pn);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_22_mbed_putc(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        Serial *ser;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_STR)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        ser = (Serial *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        ser->putc(((pPmString_t)pn)->val[0]);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_23_mbed_puts(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        Serial *ser;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pn = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pn) != OBJ_TYPE_STR)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        ser = (Serial *)((pPmInt_t)pn)->val;
+
+        /* Write value to DAC */
+        pn = NATIVE_GET_LOCAL(1);
+        ser->puts((const char *)((pPmString_t)pn)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_24_mbed_getc(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        Serial *ser;
+        int32_t n;
+
+        /* If wrong number of args, throw type exception */
+        if (NATIVE_GET_NUM_ARGS() != 1)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        ser = (Serial *)((pPmInt_t)pn)->val;
+
+        /* Return char (as string) on the stack */
+        n = ser->getc();
+        retval = string_newFromChar((uint8_t)n, &pn);
+        NATIVE_SET_TOS(pn);
+
+        return retval;
+        
+}
+
+PmReturn_t
+nat_25_mbed___init__(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pmosi;
+        pPmObj_t pmiso;
+        pPmObj_t psclk;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        SPI *spi;
+        uint8_t objid;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 4)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pmosi = NATIVE_GET_LOCAL(1);
+        pmiso = NATIVE_GET_LOCAL(2);
+        psclk = NATIVE_GET_LOCAL(3);
+        if ((OBJ_GET_TYPE(pmosi) != OBJ_TYPE_INT)
+            || (OBJ_GET_TYPE(pmiso) != OBJ_TYPE_INT)
+            || (OBJ_GET_TYPE(psclk) != OBJ_TYPE_INT))
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Instantiate the C++ object */
+        spi = new SPI(pinNumToName[((pPmInt_t)pmosi)->val],
+                      pinNumToName[((pPmInt_t)pmiso)->val],
+                      pinNumToName[((pPmInt_t)psclk)->val]);
+
+        /* Save the pointer to ser as an inaccessible attribute */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = int_new((uint32_t)spi, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pn, &objid);
+        retval = dict_setItem(pattrs, PM_NONE, pn);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_26_mbed_format(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pbits;
+        pPmObj_t pmode;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        SPI *spi;
+
+        /* Raise TypeError if wrong number of args */
+        if ((NATIVE_GET_NUM_ARGS() < 2) || (NATIVE_GET_NUM_ARGS() > 3))
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pbits = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pbits) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the mode arg if it exists */
+        pmode = PM_ZERO;
+        if (NATIVE_GET_NUM_ARGS() == 3)
+        {
+            pmode = NATIVE_GET_LOCAL(3);
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        spi = (SPI *)((pPmInt_t)pn)->val;
+
+        /* Set format args */
+        spi->format(((pPmInt_t)pbits)->val, ((pPmInt_t)pmode)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_27_mbed_frequency(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t phz;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        SPI *spi;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        phz = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(phz) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        spi = (SPI *)((pPmInt_t)pn)->val;
+
+        /* Set frequency */
+        spi->frequency(((pPmInt_t)phz)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_28_mbed_write(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t pv;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        SPI *spi;
+        int32_t r;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        pv = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pv) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        spi = (SPI *)((pPmInt_t)pn)->val;
+
+        /* Write the value and return the response */
+        r = spi->write(((pPmInt_t)pv)->val);
+        retval = int_new(r, &pn);
+        NATIVE_SET_TOS(pn);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_29_mbed___init__(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t psda;
+        pPmObj_t pscl;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        I2C *i2c;
+        uint8_t objid;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 3)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        psda = NATIVE_GET_LOCAL(1);
+        pscl = NATIVE_GET_LOCAL(2);
+        if ((OBJ_GET_TYPE(psda) != OBJ_TYPE_INT)
+            || (OBJ_GET_TYPE(pscl) != OBJ_TYPE_INT))
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Instantiate the C++ object */
+        i2c = new I2C(pinNumToName[((pPmInt_t)psda)->val],
+                      pinNumToName[((pPmInt_t)pscl)->val]);
+
+        /* Save the pointer to ser as an inaccessible attribute */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = int_new((uint32_t)i2c, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pn, &objid);
+        retval = dict_setItem(pattrs, PM_NONE, pn);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_30_mbed_frequency(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t phz;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        I2C *i2c;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        phz = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(phz) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        i2c = (I2C *)((pPmInt_t)pn)->val;
+
+        /* Set frequency */
+        i2c->frequency(((pPmInt_t)phz)->val);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_31_mbed_read(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t paddr;
+        pPmObj_t pdata;
+        pPmObj_t plen;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        I2C *i2c;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 4)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        paddr = NATIVE_GET_LOCAL(1);
+        pdata = NATIVE_GET_LOCAL(2);
+        plen = NATIVE_GET_LOCAL(3);
+        if ((OBJ_GET_TYPE(paddr) != OBJ_TYPE_INT)
+            || (OBJ_GET_TYPE(pdata) != OBJ_TYPE_STR)
+            || (OBJ_GET_TYPE(plen) != OBJ_TYPE_INT))
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        i2c = (I2C *)((pPmInt_t)pn)->val;
+
+        /* Read the bytes into the string */
+        /* WARNING: Changing the bytes of a string object is BAD. */
+        i2c->read(((pPmInt_t)paddr)->val,
+                  (char *)((pPmString_t)pdata)->val,
+                  ((pPmInt_t)plen)->val);
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_32_mbed_write(pPmFrame_t *ppframe)
+{
+
+        pPmObj_t pself;
+        pPmObj_t pn;
+        pPmObj_t paddr;
+        pPmObj_t pdata;
+        pPmObj_t plen;
+        pPmObj_t pattrs;
+        PmReturn_t retval = PM_RET_OK;
+        I2C *i2c;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 4)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        pself = NATIVE_GET_LOCAL(0);
+
+        /* Raise TypeError if arg is not the right type */
+        paddr = NATIVE_GET_LOCAL(1);
+        pdata = NATIVE_GET_LOCAL(2);
+        plen = NATIVE_GET_LOCAL(3);
+        if ((OBJ_GET_TYPE(paddr) != OBJ_TYPE_INT)
+            || (OBJ_GET_TYPE(pdata) != OBJ_TYPE_STR)
+            || (OBJ_GET_TYPE(plen) != OBJ_TYPE_INT))
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Get the the C++ instance */
+        pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs;
+        retval = dict_getItem(pattrs, PM_NONE, &pn);
+        PM_RETURN_IF_ERROR(retval);
+        i2c = (I2C *)((pPmInt_t)pn)->val;
+
+        /* Write the value and return the response */
+        i2c->write(((pPmInt_t)paddr)->val,
+                   (char *)((pPmString_t)pdata)->val,
+                   ((pPmInt_t)plen)->val);
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_33_mbed_set_led(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pled;
+    pPmObj_t pval;
+    int32_t nled;
+    int32_t nval;
+    PmReturn_t retval = PM_RET_OK;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() > 2)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* If arg is not an int, raise TypeError */
+    pled = NATIVE_GET_LOCAL(0);
+    pval = NATIVE_GET_LOCAL(1);
+    if ((OBJ_GET_TYPE(pled) != OBJ_TYPE_INT)
+        || (OBJ_GET_TYPE(pval) != OBJ_TYPE_INT))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get int value from the arg */
+    nled = ((pPmInt_t)pled)->val;
+    nval = ((pPmInt_t)pval)->val;
+
+    /* Set the LED to the given value */
+    switch (nled)
+    {
+        case 1: led1 = nval; break;
+        case 2: led2 = nval; break;
+        case 3: led3 = nval; break;
+        case 4: led4 = nval; break;
+    }
+
+    NATIVE_SET_TOS(PM_NONE);
+    return retval;
+    
+}
+
+/* Native function lookup table */
+pPmNativeFxn_t const usr_nat_fxn_table[] =
+{
+    nat_placeholder_func,
+    nat_01_mbed___init__,
+    nat_02_mbed_read_u16,
+    nat_03_mbed_read,
+    nat_04_mbed___init__,
+    nat_05_mbed_write_u16,
+    nat_06_mbed_write,
+    nat_07_mbed_read,
+    nat_08_mbed___init__,
+    nat_09_mbed_read,
+    nat_10_mbed___init__,
+    nat_11_mbed_read,
+    nat_12_mbed_write,
+    nat_13_mbed___init__,
+    nat_14_mbed_read,
+    nat_15_mbed_period,
+    nat_16_mbed_period_ms,
+    nat_17_mbed_period_us,
+    nat_18_mbed_pulsewidth,
+    nat_19_mbed_puslewidth_ms,
+    nat_20_mbed_pulsewidth_us,
+    nat_21_mbed___init__,
+    nat_22_mbed_putc,
+    nat_23_mbed_puts,
+    nat_24_mbed_getc,
+    nat_25_mbed___init__,
+    nat_26_mbed_format,
+    nat_27_mbed_frequency,
+    nat_28_mbed_write,
+    nat_29_mbed___init__,
+    nat_30_mbed_frequency,
+    nat_31_mbed_read,
+    nat_32_mbed_write,
+    nat_33_mbed_set_led,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/mbed/plat.cpp	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,333 @@
+/*
+# This file is Copyright 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.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x70
+
+
+/** PyMite platform-specific routines for ARM7 target */
+
+
+#include "mbed.h"
+#include "pm.h"
+
+
+#define CALLBACK_MS 10
+
+
+Serial serial(USBTX, USBRX, "serial");
+Ticker ticker;
+
+
+static void
+ticker_callback(void)
+{
+    PmReturn_t retval;
+
+    retval = pm_vmPeriodic(CALLBACK_MS * 1000);
+    PM_REPORT_IF_ERROR(retval);
+}
+
+
+PmReturn_t
+plat_init(void)
+{
+    serial.baud(19200);
+    serial.format(8, serial.None, 1);
+
+    ticker.attach_us(ticker_callback, CALLBACK_MS * 1000);
+
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+plat_deinit(void)
+{
+    /* Detach the callback from the ticker */
+    ticker.detach();
+
+    return PM_RET_OK;
+}
+
+
+uint8_t
+plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr)
+{
+    uint8_t b = 0;
+
+    switch (memspace)
+    {
+        case MEMSPACE_RAM:
+        case MEMSPACE_PROG:
+            b = **paddr;
+            *paddr += 1;
+            return b;
+
+        case MEMSPACE_EEPROM:
+        case MEMSPACE_SEEPROM:
+        case MEMSPACE_OTHER0:
+        case MEMSPACE_OTHER1:
+        case MEMSPACE_OTHER2:
+        case MEMSPACE_OTHER3:
+        default:
+            return 0;
+    }
+}
+
+
+PmReturn_t
+plat_getByte(uint8_t *b)
+{
+    int c;
+    PmReturn_t retval = PM_RET_OK;
+
+    c = serial.getc();
+    *b = c & 0xFF;
+
+    if (c > 0xFF)
+    {
+        PM_RAISE(retval, PM_RET_EX_IO);
+    }
+
+    return retval;
+}
+
+
+PmReturn_t
+plat_putByte(uint8_t b)
+{
+    while (!serial.writeable());
+    serial.putc(b);
+
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+plat_getMsTicks(uint32_t *r_ticks)
+{
+    *r_ticks = pm_timerMsTicks;
+
+    return PM_RET_OK;
+}
+
+
+void
+plat_reportError(PmReturn_t result)
+{
+
+#ifdef HAVE_DEBUG_INFO
+#define LEN_FNLOOKUP 26
+#define LEN_EXNLOOKUP 18
+
+    uint8_t res;
+    pPmFrame_t pframe;
+    pPmObj_t pstr;
+    PmReturn_t retval;
+    uint16_t bcindex;
+    uint16_t bcsum;
+    uint16_t linesum;
+    uint16_t len_lnotab;
+    uint8_t const *plnotab;
+    uint16_t i;
+
+    /* This table should match src/vm/fileid.txt */
+    char const * const fnlookup[LEN_FNLOOKUP] = {
+        "<no file>",
+        "codeobj.c",
+        "dict.c",
+        "frame.c",
+        "func.c",
+        "global.c",
+        "heap.c",
+        "img.c",
+        "int.c",
+        "interp.c",
+        "pmstdlib_nat.c",
+        "list.c",
+        "main.c",
+        "mem.c",
+        "module.c",
+        "obj.c",
+        "seglist.c",
+        "sli.c",
+        "strobj.c",
+        "tuple.c",
+        "seq.c",
+        "pm.c",
+        "thread.c",
+        "float.c",
+        "class.c",
+        "bytearray.c",
+    };
+
+    /* This table should match src/vm/pm.h PmReturn_t */
+    char const * const exnlookup[LEN_EXNLOOKUP] = {
+        "Exception",
+        "SystemExit",
+        "IoError",
+        "ZeroDivisionError",
+        "AssertionError",
+        "AttributeError",
+        "ImportError",
+        "IndexError",
+        "KeyError",
+        "MemoryError",
+        "NameError",
+        "SyntaxError",
+        "SystemError",
+        "TypeError",
+        "ValueError",
+        "StopIteration",
+        "Warning",
+        "OverflowError",
+    };
+
+    /* Print traceback */
+    printf("Traceback (most recent call first):\n");
+
+    /* 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)
+        {
+            printf("  Unable to get native func name.\n");
+            return;
+        }
+        else
+        {
+            printf("  %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);
+        }
+        printf("  File \"%s\", line %d, in %s\n",
+               ((pPmFrame_t)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))
+    {
+        printf("%s", exnlookup[res - PM_RET_EX]);
+    }
+    else
+    {
+        printf("Error code 0x%02X", result);
+    }
+    printf(" detected by ");
+
+    if ((gVmGlobal.errFileId > 0) && (gVmGlobal.errFileId < LEN_FNLOOKUP))
+    {
+        printf("%s:", fnlookup[gVmGlobal.errFileId]);
+    }
+    else
+    {
+        printf("FileId 0x%02X line ", gVmGlobal.errFileId);
+    }
+    printf("%d\n", gVmGlobal.errLineNum);
+
+#else /* HAVE_DEBUG_INFO */
+
+    /* Print error */
+    printf("Error:     0x%02X\n", result);
+    printf("  Release: 0x%02X\n", gVmGlobal.errVmRelease);
+    printf("  FileId:  0x%02X\n", gVmGlobal.errFileId);
+    printf("  LineNum: %d\n", gVmGlobal.errLineNum);
+
+    /* Print traceback */
+    {
+        pPmObj_t pframe;
+        pPmObj_t pstr;
+        PmReturn_t retval;
+
+        printf("Traceback (top first):\n");
+
+        /* Get the top frame */
+        pframe = (pPmObj_t)gVmGlobal.pthread->pframe;
+
+        /* If it's the native frame, print the native function name */
+        if (pframe == (pPmObj_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)
+            {
+                printf("  Unable to get native func name.\n");
+                return;
+            }
+            else
+            {
+                printf("  %s() __NATIVE__\n", ((pPmString_t)pstr)->val);
+            }
+
+            /* Get the frame that called the native frame */
+            pframe = (pPmObj_t)gVmGlobal.nativeframe.nf_back;
+        }
+
+        /* Print the remaining frame stack */
+        for (;
+             pframe != C_NULL;
+             pframe = (pPmObj_t)((pPmFrame_t)pframe)->fo_back)
+        {
+            /* The last name in the names tuple of the code obj is the name */
+            retval = tuple_getItem((pPmObj_t)((pPmFrame_t)pframe)->
+                                   fo_func->f_co->co_names, -1, &pstr);
+            if ((retval) != PM_RET_OK) break;
+
+            printf("  %s()\n", ((pPmString_t)pstr)->val);
+        }
+        printf("  <module>.\n");
+    }
+#endif /* HAVE_DEBUG_INFO */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/mbed/plat.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,22 @@
+/*
+# This file is Copyright 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.
+*/
+
+#ifndef _PLAT_H_
+#define _PLAT_H_
+
+#define PM_FLOAT_LITTLE_ENDIAN
+#define PM_PLAT_HEAP_ATTR __attribute__((aligned (4)))
+#define PM_PLAT_POINTER_SIZE 4
+
+#endif /* _PLAT_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/mbed/pmfeatures.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,16 @@
+/* Automatically generated by ../../tools/pmGenPmFeatures.py on Sat Mar 02 20:27:03 2013.  DO NOT EDIT. */
+#define HAVE_PRINT
+#define HAVE_CLASSES
+#define HAVE_REPLICATION
+#define HAVE_DEFAULTARGS
+#define HAVE_DEL
+#define HAVE_BACKTICK
+#define HAVE_FLOAT
+#define HAVE_GC
+#define HAVE_STRING_FORMAT
+#define HAVE_AUTOBOX
+#define HAVE_ASSERT
+#define HAVE_CLOSURES
+#define HAVE_GENERATORS
+#define HAVE_IMPORTS
+#define HAVE_DEBUG_INFO
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/mbed/pmstdlib_img.cpp	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,710 @@
+/**
+ * PyMite library image file.
+ *
+ * Automatically created from:
+ *     ../../lib/__bi.py
+ *    ../../lib/dict.py
+ *    ../../lib/list.py
+ *    ../../lib/string.py
+ *    ../../lib/sys.py
+ *    ../../lib/ipm.py
+ *    img-list-terminator
+ * by pmImgCreator.py on
+ * Sat Mar 02 20:27:03 2013.
+ * 
+ * Byte count: 5264
+ * 
+ * Selected memspace type: FLASH
+ * 
+ * DO NOT EDIT THIS FILE.
+ * ANY CHANGES WILL BE LOST.
+ */
+
+/* Place the image into FLASH */
+#ifdef __cplusplus
+extern
+#endif
+unsigned char const
+#if defined(__AVR__)
+__attribute__((progmem))
+#endif
+stdlib_img[] =
+{
+
+
+/* ../../lib/__bi.py */
+    0x0A, 0x03, 0x06, 0x00, 0x40, 0x03, 0x00, 0x00, 
+    0x12, 0x00, 0x04, 0x19, 0x03, 0x03, 0x00, 0x61, 
+    0x62, 0x73, 0x03, 0x03, 0x00, 0x63, 0x68, 0x72, 
+    0x03, 0x03, 0x00, 0x64, 0x69, 0x72, 0x03, 0x04, 
+    0x00, 0x65, 0x76, 0x61, 0x6C, 0x03, 0x06, 0x00, 
+    0x66, 0x69, 0x6C, 0x74, 0x65, 0x72, 0x03, 0x07, 
+    0x00, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x73, 
+    0x03, 0x02, 0x00, 0x69, 0x64, 0x03, 0x03, 0x00, 
+    0x6C, 0x65, 0x6E, 0x03, 0x06, 0x00, 0x6C, 0x6F, 
+    0x63, 0x61, 0x6C, 0x73, 0x03, 0x03, 0x00, 0x6D, 
+    0x61, 0x70, 0x03, 0x03, 0x00, 0x6F, 0x72, 0x64, 
+    0x03, 0x03, 0x00, 0x70, 0x6F, 0x77, 0x03, 0x05, 
+    0x00, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x03, 0x03, 
+    0x00, 0x73, 0x75, 0x6D, 0x03, 0x04, 0x00, 0x74, 
+    0x79, 0x70, 0x65, 0x03, 0x02, 0x00, 0x43, 0x6F, 
+    0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, 
+    0x65, 0x5F, 0x5F, 0x03, 0x06, 0x00, 0x6F, 0x62, 
+    0x6A, 0x65, 0x63, 0x74, 0x03, 0x09, 0x00, 0x45, 
+    0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 
+    0x03, 0x0E, 0x00, 0x41, 0x73, 0x73, 0x65, 0x72, 
+    0x74, 0x69, 0x6F, 0x6E, 0x45, 0x72, 0x72, 0x6F, 
+    0x72, 0x03, 0x04, 0x00, 0x63, 0x6F, 0x64, 0x65, 
+    0x03, 0x09, 0x00, 0x47, 0x65, 0x6E, 0x65, 0x72, 
+    0x61, 0x74, 0x6F, 0x72, 0x03, 0x06, 0x00, 0x69, 
+    0x73, 0x6D, 0x61, 0x69, 0x6E, 0x03, 0x04, 0x00, 
+    0x5F, 0x5F, 0x6D, 0x64, 0x03, 0x04, 0x00, 0x5F, 
+    0x5F, 0x62, 0x69, 0x03, 0x2E, 0x00, 0x09, 0x05, 
+    0x09, 0x26, 0x09, 0x5B, 0x09, 0x64, 0x09, 0x04, 
+    0x09, 0x19, 0x09, 0x1B, 0x09, 0x43, 0x09, 0x15, 
+    0x09, 0x0E, 0x09, 0x22, 0x09, 0x04, 0x09, 0x61, 
+    0x09, 0x68, 0x09, 0x25, 0x09, 0x23, 0x06, 0x06, 
+    0x13, 0x07, 0x16, 0x03, 0x16, 0x02, 0x09, 0x0B, 
+    0x16, 0xA2, 0x09, 0x3B, 0x03, 0x12, 0x00, 0x2E, 
+    0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 
+    0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x1D, 0x0A, 0x4B, 0x00, 0x01, 0x43, 
+    0x03, 0x01, 0x00, 0x12, 0x00, 0x04, 0x01, 0x03, 
+    0x03, 0x00, 0x61, 0x62, 0x73, 0x03, 0x02, 0x00, 
+    0x00, 0x02, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 
+    0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x5F, 
+    0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 0x00, 0x04, 
+    0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 
+    0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0B, 
+    0x66, 0x02, 0x00, 0x7C, 0x00, 0x00, 0x64, 0x01, 
+    0x00, 0x6A, 0x00, 0x00, 0x19, 0x53, 0x0B, 0x01, 
+    0x00, 0x00, 0x0B, 0x01, 0x01, 0x00, 0x0B, 0x03, 
+    0x02, 0x00, 0x0A, 0x64, 0x00, 0x02, 0x43, 0x04, 
+    0x04, 0x00, 0xFC, 0x00, 0x04, 0x01, 0x03, 0x06, 
+    0x00, 0x66, 0x69, 0x6C, 0x74, 0x65, 0x72, 0x03, 
+    0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, 
+    0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 
+    0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x67, 0x00, 
+    0x00, 0x04, 0x7D, 0x02, 0x00, 0x7C, 0x01, 0x00, 
+    0x44, 0x5D, 0x1E, 0x00, 0x7D, 0x03, 0x00, 0x7C, 
+    0x00, 0x00, 0x7C, 0x03, 0x00, 0x83, 0x01, 0x00, 
+    0x6F, 0x0B, 0x00, 0x01, 0x7C, 0x02, 0x00, 0x7C, 
+    0x03, 0x00, 0x12, 0x71, 0x0B, 0x00, 0x01, 0x71, 
+    0x0B, 0x00, 0x7E, 0x02, 0x00, 0x53, 0x0B, 0x00, 
+    0x03, 0x00, 0x0B, 0x01, 0x04, 0x00, 0x0B, 0x01, 
+    0x05, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x0A, 0x9C, 
+    0x00, 0x02, 0x43, 0x04, 0x05, 0x00, 0x8C, 0x01, 
+    0x04, 0x03, 0x03, 0x04, 0x00, 0x4E, 0x6F, 0x6E, 
+    0x65, 0x03, 0x03, 0x00, 0x6C, 0x65, 0x6E, 0x03, 
+    0x03, 0x00, 0x6D, 0x61, 0x70, 0x03, 0x0E, 0x00, 
+    0x00, 0x02, 0x13, 0x03, 0x06, 0x01, 0x07, 0x00, 
+    0x06, 0x01, 0x10, 0x01, 0x0E, 0x03, 0x03, 0x12, 
+    0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 
+    0x69, 0x62, 0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 
+    0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 
+    0x04, 0x00, 0x64, 0x00, 0x00, 0x67, 0x01, 0x00, 
+    0x74, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x83, 0x01, 
+    0x00, 0x14, 0x7D, 0x02, 0x00, 0x64, 0x01, 0x00, 
+    0x7D, 0x03, 0x00, 0x78, 0x28, 0x00, 0x7C, 0x01, 
+    0x00, 0x44, 0x5D, 0x20, 0x00, 0x7D, 0x04, 0x00, 
+    0x7C, 0x00, 0x00, 0x7C, 0x04, 0x00, 0x83, 0x01, 
+    0x00, 0x7C, 0x02, 0x00, 0x7C, 0x03, 0x00, 0x3C, 
+    0x7C, 0x03, 0x00, 0x64, 0x02, 0x00, 0x37, 0x7D, 
+    0x03, 0x00, 0x71, 0x20, 0x00, 0x57, 0x7C, 0x02, 
+    0x00, 0x53, 0x0B, 0x01, 0x07, 0x00, 0x0A, 0x39, 
+    0x00, 0x02, 0x43, 0x02, 0x02, 0x00, 0xBC, 0x01, 
+    0x04, 0x01, 0x03, 0x03, 0x00, 0x70, 0x6F, 0x77, 
+    0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 
+    0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 
+    0x62, 0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, 0x70, 
+    0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x7C, 
+    0x00, 0x00, 0x7C, 0x01, 0x00, 0x13, 0x53, 0x0B, 
+    0x03, 0x08, 0x00, 0x0B, 0x01, 0x09, 0x00, 0x0B, 
+    0x01, 0x0A, 0x00, 0x0B, 0x01, 0x0B, 0x00, 0x03, 
+    0x03, 0x00, 0x54, 0x42, 0x44, 0x03, 0x06, 0x00, 
+    0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x0A, 0x53, 
+    0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0xD7, 0x02, 
+    0x04, 0x03, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 
+    0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 
+    0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 
+    0x5F, 0x5F, 0x03, 0x06, 0x00, 0x6F, 0x62, 0x6A, 
+    0x65, 0x63, 0x74, 0x03, 0x02, 0x00, 0x06, 0x01, 
+    0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 
+    0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x5F, 0x5F, 0x62, 
+    0x69, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x00, 0x04, 
+    0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x52, 
+    0x53, 0x03, 0x09, 0x00, 0x45, 0x78, 0x63, 0x65, 
+    0x70, 0x74, 0x69, 0x6F, 0x6E, 0x0A, 0x56, 0x00, 
+    0x00, 0x42, 0x01, 0x00, 0x00, 0xDE, 0x02, 0x04, 
+    0x03, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 
+    0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 
+    0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 
+    0x5F, 0x03, 0x09, 0x00, 0x45, 0x78, 0x63, 0x65, 
+    0x70, 0x74, 0x69, 0x6F, 0x6E, 0x03, 0x02, 0x00, 
+    0x06, 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 
+    0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x5F, 
+    0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 0x00, 0x04, 
+    0x00, 0x04, 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 
+    0x00, 0x52, 0x53, 0x03, 0x0E, 0x00, 0x41, 0x73, 
+    0x73, 0x65, 0x72, 0x74, 0x69, 0x6F, 0x6E, 0x45, 
+    0x72, 0x72, 0x6F, 0x72, 0x0A, 0x5B, 0x00, 0x00, 
+    0x42, 0x01, 0x00, 0x00, 0xE1, 0x02, 0x04, 0x03, 
+    0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, 
+    0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 0x5F, 
+    0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 0x5F, 
+    0x03, 0x0E, 0x00, 0x41, 0x73, 0x73, 0x65, 0x72, 
+    0x74, 0x69, 0x6F, 0x6E, 0x45, 0x72, 0x72, 0x6F, 
+    0x72, 0x03, 0x02, 0x00, 0x06, 0x01, 0x03, 0x12, 
+    0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 
+    0x69, 0x62, 0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x00, 0x04, 0x00, 0x65, 
+    0x00, 0x00, 0x5A, 0x01, 0x00, 0x52, 0x53, 0x01, 
+    0xE4, 0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0x47, 
+    0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x6F, 0x72, 
+    0x0A, 0xE3, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 
+    0xEE, 0x02, 0x04, 0x06, 0x03, 0x08, 0x00, 0x5F, 
+    0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 
+    0x0A, 0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 
+    0x6C, 0x65, 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 
+    0x5F, 0x69, 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 
+    0x04, 0x00, 0x6E, 0x65, 0x78, 0x74, 0x03, 0x04, 
+    0x00, 0x73, 0x65, 0x6E, 0x64, 0x03, 0x09, 0x00, 
+    0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x6F, 
+    0x72, 0x03, 0x06, 0x00, 0x06, 0x02, 0x09, 0x37, 
+    0x09, 0x04, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 
+    0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x5F, 
+    0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 0x00, 0x04, 
+    0x03, 0x0B, 0x02, 0x0C, 0x00, 0x0A, 0x4D, 0x00, 
+    0x01, 0x43, 0x02, 0x01, 0x00, 0x27, 0x03, 0x04, 
+    0x03, 0x03, 0x04, 0x00, 0x73, 0x65, 0x6E, 0x64, 
+    0x03, 0x04, 0x00, 0x4E, 0x6F, 0x6E, 0x65, 0x03, 
+    0x04, 0x00, 0x6E, 0x65, 0x78, 0x74, 0x03, 0x02, 
+    0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, 
+    0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 
+    0x5F, 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 0x00, 
+    0x04, 0x01, 0x00, 0x04, 0x00, 0x7C, 0x00, 0x00, 
+    0x69, 0x00, 0x00, 0x64, 0x00, 0x00, 0x83, 0x01, 
+    0x00, 0x53, 0x0B, 0x02, 0x0D, 0x00, 0x04, 0x00, 
+    0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 
+    0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 
+    0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 
+    0x00, 0x52, 0x53, 0x0B, 0x00, 0x0E, 0x00, 0x00, 
+    0x04, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x00, 0x00, 0x64, 0x01, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 0x02, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 
+    0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 
+    0x64, 0x04, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 
+    0x00, 0x64, 0x05, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x05, 0x00, 0x64, 0x06, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x06, 0x00, 0x64, 0x07, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x07, 0x00, 0x64, 0x08, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x08, 0x00, 0x64, 0x09, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x09, 0x00, 0x64, 0x0A, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x0A, 0x00, 0x64, 
+    0x0B, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x0B, 0x00, 
+    0x64, 0x0C, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x0C, 
+    0x00, 0x64, 0x0D, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x0D, 0x00, 0x64, 0x0E, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x0E, 0x00, 0x64, 0x0F, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x0F, 0x00, 0x64, 0x10, 0x00, 0x5A, 
+    0x10, 0x00, 0x64, 0x11, 0x00, 0x64, 0x1C, 0x00, 
+    0x64, 0x12, 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 
+    0x00, 0x59, 0x5A, 0x11, 0x00, 0x64, 0x13, 0x00, 
+    0x65, 0x11, 0x00, 0x66, 0x01, 0x00, 0x64, 0x14, 
+    0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 
+    0x5A, 0x12, 0x00, 0x64, 0x15, 0x00, 0x65, 0x12, 
+    0x00, 0x66, 0x01, 0x00, 0x64, 0x16, 0x00, 0x84, 
+    0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x13, 
+    0x00, 0x64, 0x17, 0x00, 0x65, 0x13, 0x00, 0x5F, 
+    0x14, 0x00, 0x64, 0x18, 0x00, 0x65, 0x11, 0x00, 
+    0x66, 0x01, 0x00, 0x64, 0x19, 0x00, 0x84, 0x00, 
+    0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x15, 0x00, 
+    0x64, 0x1A, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x16, 
+    0x00, 0x68, 0x00, 0x00, 0x5A, 0x17, 0x00, 0x64, 
+    0x1B, 0x00, 0x53, 
+
+/* ../../lib/dict.py */
+    0x0A, 0x0A, 0x03, 0x00, 0x40, 0x03, 0x00, 0x00, 
+    0x0C, 0x00, 0x04, 0x08, 0x03, 0x08, 0x00, 0x5F, 
+    0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 
+    0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, 0x6F, 0x62, 
+    0x6F, 0x78, 0x03, 0x05, 0x00, 0x63, 0x6C, 0x65, 
+    0x61, 0x72, 0x03, 0x04, 0x00, 0x6B, 0x65, 0x79, 
+    0x73, 0x03, 0x07, 0x00, 0x68, 0x61, 0x73, 0x5F, 
+    0x6B, 0x65, 0x79, 0x03, 0x06, 0x00, 0x76, 0x61, 
+    0x6C, 0x75, 0x65, 0x73, 0x03, 0x06, 0x00, 0x75, 
+    0x70, 0x64, 0x61, 0x74, 0x65, 0x03, 0x04, 0x00, 
+    0x64, 0x69, 0x63, 0x74, 0x03, 0x0C, 0x00, 0x06, 
+    0x03, 0x13, 0x0E, 0x09, 0x18, 0x09, 0x2B, 0x09, 
+    0x04, 0x09, 0x2B, 0x03, 0x12, 0x00, 0x2E, 0x2E, 
+    0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 
+    0x64, 0x69, 0x63, 0x74, 0x2E, 0x70, 0x79, 0x00, 
+    0x04, 0x0A, 0x03, 0x04, 0x00, 0x64, 0x69, 0x63, 
+    0x74, 0x03, 0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, 
+    0x6F, 0x62, 0x6F, 0x78, 0x0A, 0xE0, 0x01, 0x00, 
+    0x42, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x04, 0x07, 
+    0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, 
+    0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 0x5F, 
+    0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 0x5F, 
+    0x03, 0x05, 0x00, 0x63, 0x6C, 0x65, 0x61, 0x72, 
+    0x03, 0x04, 0x00, 0x6B, 0x65, 0x79, 0x73, 0x03, 
+    0x07, 0x00, 0x68, 0x61, 0x73, 0x5F, 0x6B, 0x65, 
+    0x79, 0x03, 0x06, 0x00, 0x76, 0x61, 0x6C, 0x75, 
+    0x65, 0x73, 0x03, 0x08, 0x00, 0x5F, 0x41, 0x75, 
+    0x74, 0x6F, 0x62, 0x6F, 0x78, 0x03, 0x08, 0x00, 
+    0x06, 0x01, 0x09, 0x03, 0x09, 0x03, 0x09, 0x03, 
+    0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 
+    0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x64, 0x69, 0x63, 
+    0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x04, 0x0A, 
+    0x4E, 0x00, 0x01, 0x43, 0x02, 0x01, 0x00, 0x10, 
+    0x00, 0x04, 0x03, 0x03, 0x05, 0x00, 0x63, 0x6C, 
+    0x65, 0x61, 0x72, 0x03, 0x03, 0x00, 0x6F, 0x62, 
+    0x6A, 0x03, 0x05, 0x00, 0x63, 0x6C, 0x65, 0x61, 
+    0x72, 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 
+    0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 
+    0x69, 0x62, 0x2F, 0x64, 0x69, 0x63, 0x74, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 
+    0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 
+    0x00, 0x83, 0x01, 0x00, 0x53, 0x0A, 0x4C, 0x00, 
+    0x01, 0x43, 0x02, 0x01, 0x00, 0x13, 0x00, 0x04, 
+    0x03, 0x03, 0x04, 0x00, 0x6B, 0x65, 0x79, 0x73, 
+    0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x04, 
+    0x00, 0x6B, 0x65, 0x79, 0x73, 0x03, 0x02, 0x00, 
+    0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 
+    0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x64, 
+    0x69, 0x63, 0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 
+    0x01, 0x00, 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 
+    0x00, 0x00, 0x69, 0x01, 0x00, 0x83, 0x01, 0x00, 
+    0x53, 0x0A, 0x55, 0x00, 0x02, 0x43, 0x03, 0x02, 
+    0x00, 0x16, 0x00, 0x04, 0x03, 0x03, 0x07, 0x00, 
+    0x68, 0x61, 0x73, 0x5F, 0x6B, 0x65, 0x79, 0x03, 
+    0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x07, 0x00, 
+    0x68, 0x61, 0x73, 0x5F, 0x6B, 0x65, 0x79, 0x03, 
+    0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, 
+    0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 
+    0x2F, 0x64, 0x69, 0x63, 0x74, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, 0x00, 
+    0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, 0x7C, 
+    0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x0A, 0x50, 
+    0x00, 0x01, 0x43, 0x02, 0x01, 0x00, 0x19, 0x00, 
+    0x04, 0x03, 0x03, 0x06, 0x00, 0x76, 0x61, 0x6C, 
+    0x75, 0x65, 0x73, 0x03, 0x03, 0x00, 0x6F, 0x62, 
+    0x6A, 0x03, 0x06, 0x00, 0x76, 0x61, 0x6C, 0x75, 
+    0x65, 0x73, 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 
+    0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 
+    0x6C, 0x69, 0x62, 0x2F, 0x64, 0x69, 0x63, 0x74, 
+    0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 
+    0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 
+    0x01, 0x00, 0x83, 0x01, 0x00, 0x53, 0x04, 0x00, 
+    0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 
+    0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 
+    0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 
+    0x00, 0x64, 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x05, 0x00, 0x52, 0x53, 0x0B, 0x01, 0x0F, 0x00, 
+    0x0B, 0x01, 0x10, 0x00, 0x0A, 0x3F, 0x00, 0x02, 
+    0x43, 0x02, 0x02, 0x00, 0x60, 0x00, 0x04, 0x01, 
+    0x03, 0x07, 0x00, 0x68, 0x61, 0x73, 0x5F, 0x6B, 
+    0x65, 0x79, 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 
+    0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 
+    0x6C, 0x69, 0x62, 0x2F, 0x64, 0x69, 0x63, 0x74, 
+    0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 
+    0x00, 0x7C, 0x01, 0x00, 0x7C, 0x00, 0x00, 0x6A, 
+    0x06, 0x00, 0x53, 0x0B, 0x01, 0x11, 0x00, 0x0B, 
+    0x02, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 
+    0x64, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x64, 0x01, 
+    0x00, 0x64, 0x09, 0x00, 0x64, 0x02, 0x00, 0x84, 
+    0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x01, 
+    0x00, 0x64, 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x02, 0x00, 0x64, 0x04, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x03, 0x00, 0x64, 0x05, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x04, 0x00, 0x64, 0x06, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x05, 0x00, 0x64, 0x07, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x06, 0x00, 0x64, 0x08, 
+    0x00, 0x53, 
+
+/* ../../lib/list.py */
+    0x0A, 0x41, 0x05, 0x00, 0x40, 0x03, 0x00, 0x00, 
+    0x10, 0x00, 0x04, 0x0A, 0x03, 0x08, 0x00, 0x5F, 
+    0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 
+    0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, 0x6F, 0x62, 
+    0x6F, 0x78, 0x03, 0x06, 0x00, 0x61, 0x70, 0x70, 
+    0x65, 0x6E, 0x64, 0x03, 0x05, 0x00, 0x63, 0x6F, 
+    0x75, 0x6E, 0x74, 0x03, 0x06, 0x00, 0x65, 0x78, 
+    0x74, 0x65, 0x6E, 0x64, 0x03, 0x05, 0x00, 0x69, 
+    0x6E, 0x64, 0x65, 0x78, 0x03, 0x06, 0x00, 0x69, 
+    0x6E, 0x73, 0x65, 0x72, 0x74, 0x03, 0x03, 0x00, 
+    0x70, 0x6F, 0x70, 0x03, 0x06, 0x00, 0x72, 0x65, 
+    0x6D, 0x6F, 0x76, 0x65, 0x03, 0x04, 0x00, 0x6C, 
+    0x69, 0x73, 0x74, 0x03, 0x10, 0x00, 0x06, 0x02, 
+    0x13, 0x1A, 0x09, 0x17, 0x09, 0x08, 0x09, 0x05, 
+    0x09, 0x22, 0x09, 0x27, 0x09, 0x37, 0x03, 0x12, 
+    0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 
+    0x69, 0x62, 0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x0C, 0x03, 0x04, 0x00, 
+    0x6C, 0x69, 0x73, 0x74, 0x03, 0x08, 0x00, 0x5F, 
+    0x41, 0x75, 0x74, 0x6F, 0x62, 0x6F, 0x78, 0x0A, 
+    0x4D, 0x03, 0x00, 0x42, 0x02, 0x00, 0x00, 0x12, 
+    0x00, 0x04, 0x0B, 0x03, 0x08, 0x00, 0x5F, 0x5F, 
+    0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 
+    0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 
+    0x65, 0x5F, 0x5F, 0x03, 0x06, 0x00, 0x61, 0x70, 
+    0x70, 0x65, 0x6E, 0x64, 0x03, 0x05, 0x00, 0x63, 
+    0x6F, 0x75, 0x6E, 0x74, 0x03, 0x06, 0x00, 0x65, 
+    0x78, 0x74, 0x65, 0x6E, 0x64, 0x03, 0x05, 0x00, 
+    0x69, 0x6E, 0x64, 0x65, 0x78, 0x03, 0x06, 0x00, 
+    0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x03, 0x04, 
+    0x00, 0x4E, 0x6F, 0x6E, 0x65, 0x03, 0x03, 0x00, 
+    0x70, 0x6F, 0x70, 0x03, 0x06, 0x00, 0x72, 0x65, 
+    0x6D, 0x6F, 0x76, 0x65, 0x03, 0x08, 0x00, 0x5F, 
+    0x41, 0x75, 0x74, 0x6F, 0x62, 0x6F, 0x78, 0x03, 
+    0x0E, 0x00, 0x06, 0x01, 0x09, 0x03, 0x09, 0x03, 
+    0x09, 0x03, 0x09, 0x03, 0x09, 0x03, 0x0C, 0x06, 
+    0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 
+    0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x6C, 0x69, 0x73, 
+    0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x08, 0x0A, 
+    0x53, 0x00, 0x02, 0x43, 0x03, 0x02, 0x00, 0x13, 
+    0x00, 0x04, 0x03, 0x03, 0x06, 0x00, 0x61, 0x70, 
+    0x70, 0x65, 0x6E, 0x64, 0x03, 0x03, 0x00, 0x6F, 
+    0x62, 0x6A, 0x03, 0x06, 0x00, 0x61, 0x70, 0x70, 
+    0x65, 0x6E, 0x64, 0x03, 0x02, 0x00, 0x00, 0x01, 
+    0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 
+    0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x6C, 0x69, 0x73, 
+    0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 
+    0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, 
+    0x69, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x83, 0x02, 
+    0x00, 0x53, 0x0A, 0x51, 0x00, 0x02, 0x43, 0x03, 
+    0x02, 0x00, 0x16, 0x00, 0x04, 0x03, 0x03, 0x05, 
+    0x00, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x03, 0x03, 
+    0x00, 0x6F, 0x62, 0x6A, 0x03, 0x05, 0x00, 0x63, 
+    0x6F, 0x75, 0x6E, 0x74, 0x03, 0x02, 0x00, 0x00, 
+    0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 
+    0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x6C, 0x69, 
+    0x73, 0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 
+    0x00, 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 
+    0x00, 0x69, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x83, 
+    0x02, 0x00, 0x53, 0x0A, 0x53, 0x00, 0x02, 0x43, 
+    0x03, 0x02, 0x00, 0x19, 0x00, 0x04, 0x03, 0x03, 
+    0x06, 0x00, 0x65, 0x78, 0x74, 0x65, 0x6E, 0x64, 
+    0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x06, 
+    0x00, 0x65, 0x78, 0x74, 0x65, 0x6E, 0x64, 0x03, 
+    0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, 
+    0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 
+    0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, 0x00, 
+    0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, 0x7C, 
+    0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x0A, 0x51, 
+    0x00, 0x02, 0x43, 0x03, 0x02, 0x00, 0x1C, 0x00, 
+    0x04, 0x03, 0x03, 0x05, 0x00, 0x69, 0x6E, 0x64, 
+    0x65, 0x78, 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 
+    0x03, 0x05, 0x00, 0x69, 0x6E, 0x64, 0x65, 0x78, 
+    0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 
+    0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 
+    0x62, 0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 
+    0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, 
+    0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, 
+    0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x0A, 
+    0x56, 0x00, 0x03, 0x43, 0x04, 0x03, 0x00, 0x1F, 
+    0x00, 0x04, 0x03, 0x03, 0x06, 0x00, 0x69, 0x6E, 
+    0x73, 0x65, 0x72, 0x74, 0x03, 0x03, 0x00, 0x6F, 
+    0x62, 0x6A, 0x03, 0x06, 0x00, 0x69, 0x6E, 0x73, 
+    0x65, 0x72, 0x74, 0x03, 0x02, 0x00, 0x00, 0x01, 
+    0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 
+    0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x6C, 0x69, 0x73, 
+    0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 
+    0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, 
+    0x69, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x7C, 0x02, 
+    0x00, 0x83, 0x03, 0x00, 0x53, 0x0A, 0x77, 0x00, 
+    0x02, 0x43, 0x03, 0x02, 0x00, 0x22, 0x00, 0x04, 
+    0x04, 0x03, 0x04, 0x00, 0x4E, 0x6F, 0x6E, 0x65, 
+    0x03, 0x03, 0x00, 0x70, 0x6F, 0x70, 0x03, 0x03, 
+    0x00, 0x6F, 0x62, 0x6A, 0x03, 0x03, 0x00, 0x70, 
+    0x6F, 0x70, 0x03, 0x06, 0x00, 0x00, 0x01, 0x0D, 
+    0x01, 0x0E, 0x02, 0x03, 0x12, 0x00, 0x2E, 0x2E, 
+    0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 
+    0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 0x79, 0x00, 
+    0x04, 0x01, 0x00, 0x04, 0x00, 0x7C, 0x01, 0x00, 
+    0x64, 0x00, 0x00, 0x6A, 0x02, 0x00, 0x6F, 0x0E, 
+    0x00, 0x01, 0x74, 0x01, 0x00, 0x7C, 0x00, 0x00, 
+    0x69, 0x02, 0x00, 0x83, 0x01, 0x00, 0x53, 0x01, 
+    0x74, 0x01, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x02, 
+    0x00, 0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 
+    0x64, 0x00, 0x00, 0x53, 0x0A, 0x53, 0x00, 0x02, 
+    0x43, 0x03, 0x02, 0x00, 0x28, 0x00, 0x04, 0x03, 
+    0x03, 0x06, 0x00, 0x72, 0x65, 0x6D, 0x6F, 0x76, 
+    0x65, 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 
+    0x06, 0x00, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 
+    0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 
+    0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 
+    0x62, 0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 
+    0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, 
+    0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, 
+    0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x00, 
+    0x04, 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 
+    0x64, 0x00, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 
+    0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x03, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x04, 0x00, 0x64, 0x03, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x05, 0x00, 0x64, 0x04, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x06, 0x00, 0x64, 0x07, 0x00, 
+    0x64, 0x05, 0x00, 0x84, 0x01, 0x00, 0x5A, 0x08, 
+    0x00, 0x64, 0x06, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x09, 0x00, 0x52, 0x53, 0x0B, 0x02, 0x13, 0x00, 
+    0x0A, 0x7D, 0x00, 0x02, 0x43, 0x03, 0x04, 0x00, 
+    0x43, 0x00, 0x04, 0x01, 0x03, 0x05, 0x00, 0x63, 
+    0x6F, 0x75, 0x6E, 0x74, 0x03, 0x0C, 0x00, 0x00, 
+    0x01, 0x06, 0x01, 0x07, 0x00, 0x06, 0x01, 0x0D, 
+    0x01, 0x12, 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, 
+    0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 
+    0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 0x79, 0x00, 
+    0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 
+    0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x64, 
+    0x01, 0x00, 0x7D, 0x02, 0x00, 0x78, 0x29, 0x00, 
+    0x7C, 0x00, 0x00, 0x44, 0x5D, 0x21, 0x00, 0x7D, 
+    0x03, 0x00, 0x7C, 0x03, 0x00, 0x7C, 0x01, 0x00, 
+    0x6A, 0x02, 0x00, 0x6F, 0x0E, 0x00, 0x01, 0x7C, 
+    0x02, 0x00, 0x64, 0x02, 0x00, 0x17, 0x7D, 0x02, 
+    0x00, 0x71, 0x0D, 0x00, 0x01, 0x71, 0x0D, 0x00, 
+    0x57, 0x7C, 0x02, 0x00, 0x53, 0x0A, 0x63, 0x00, 
+    0x02, 0x43, 0x04, 0x03, 0x00, 0x4B, 0x00, 0x04, 
+    0x02, 0x03, 0x06, 0x00, 0x61, 0x70, 0x70, 0x65, 
+    0x6E, 0x64, 0x03, 0x06, 0x00, 0x65, 0x78, 0x74, 
+    0x65, 0x6E, 0x64, 0x03, 0x06, 0x00, 0x00, 0x01, 
+    0x07, 0x00, 0x06, 0x01, 0x03, 0x12, 0x00, 0x2E, 
+    0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 
+    0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x78, 0x1B, 
+    0x00, 0x7C, 0x01, 0x00, 0x44, 0x5D, 0x13, 0x00, 
+    0x7D, 0x02, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 
+    0x00, 0x7C, 0x02, 0x00, 0x83, 0x02, 0x00, 0x01, 
+    0x71, 0x07, 0x00, 0x57, 0x64, 0x00, 0x00, 0x53, 
+    0x0B, 0x02, 0x14, 0x00, 0x0B, 0x03, 0x15, 0x00, 
+    0x0B, 0x02, 0x16, 0x00, 0x0B, 0x02, 0x17, 0x00, 
+    0x00, 0x04, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 
+    0x5A, 0x00, 0x00, 0x64, 0x01, 0x00, 0x64, 0x0B, 
+    0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 0x83, 
+    0x00, 0x00, 0x59, 0x5A, 0x01, 0x00, 0x64, 0x03, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 
+    0x04, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 
+    0x64, 0x05, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 
+    0x00, 0x64, 0x06, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x05, 0x00, 0x64, 0x07, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x06, 0x00, 0x64, 0x08, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x07, 0x00, 0x64, 0x09, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x08, 0x00, 0x64, 0x0A, 0x00, 
+    0x53, 
+
+/* ../../lib/string.py */
+    0x0A, 0xBF, 0x03, 0x00, 0x40, 0x03, 0x00, 0x00, 
+    0x10, 0x00, 0x04, 0x0B, 0x03, 0x07, 0x00, 0x5F, 
+    0x5F, 0x64, 0x6F, 0x63, 0x5F, 0x5F, 0x03, 0x08, 
+    0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 
+    0x5F, 0x03, 0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, 
+    0x6F, 0x62, 0x6F, 0x78, 0x03, 0x06, 0x00, 0x64, 
+    0x69, 0x67, 0x69, 0x74, 0x73, 0x03, 0x09, 0x00, 
+    0x68, 0x65, 0x78, 0x64, 0x69, 0x67, 0x69, 0x74, 
+    0x73, 0x03, 0x07, 0x00, 0x6C, 0x65, 0x74, 0x74, 
+    0x65, 0x72, 0x73, 0x03, 0x04, 0x00, 0x61, 0x74, 
+    0x6F, 0x69, 0x03, 0x05, 0x00, 0x63, 0x6F, 0x75, 
+    0x6E, 0x74, 0x03, 0x04, 0x00, 0x66, 0x69, 0x6E, 
+    0x64, 0x03, 0x04, 0x00, 0x6A, 0x6F, 0x69, 0x6E, 
+    0x03, 0x06, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 
+    0x67, 0x03, 0x12, 0x00, 0x06, 0x03, 0x06, 0x03, 
+    0x13, 0x0B, 0x06, 0x01, 0x06, 0x01, 0x06, 0x07, 
+    0x09, 0x45, 0x09, 0x57, 0x09, 0x3B, 0x03, 0x14, 
+    0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 
+    0x69, 0x62, 0x2F, 0x73, 0x74, 0x72, 0x69, 0x6E, 
+    0x67, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x0E, 0x00, 
+    0x03, 0x06, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 
+    0x67, 0x03, 0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, 
+    0x6F, 0x62, 0x6F, 0x78, 0x0A, 0x81, 0x01, 0x00, 
+    0x42, 0x01, 0x00, 0x00, 0x16, 0x00, 0x04, 0x06, 
+    0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, 
+    0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 0x5F, 
+    0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 0x5F, 
+    0x03, 0x04, 0x00, 0x6A, 0x6F, 0x69, 0x6E, 0x03, 
+    0x05, 0x00, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x03, 
+    0x04, 0x00, 0x66, 0x69, 0x6E, 0x64, 0x03, 0x08, 
+    0x00, 0x5F, 0x41, 0x75, 0x74, 0x6F, 0x62, 0x6F, 
+    0x78, 0x03, 0x06, 0x00, 0x06, 0x01, 0x09, 0x03, 
+    0x09, 0x03, 0x03, 0x14, 0x00, 0x2E, 0x2E, 0x2F, 
+    0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x73, 
+    0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x03, 0x0A, 0x51, 0x00, 0x02, 0x43, 
+    0x03, 0x02, 0x00, 0x17, 0x00, 0x04, 0x03, 0x03, 
+    0x04, 0x00, 0x6A, 0x6F, 0x69, 0x6E, 0x03, 0x03, 
+    0x00, 0x6F, 0x62, 0x6A, 0x03, 0x04, 0x00, 0x6A, 
+    0x6F, 0x69, 0x6E, 0x03, 0x02, 0x00, 0x00, 0x01, 
+    0x03, 0x14, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 
+    0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x73, 0x74, 0x72, 
+    0x69, 0x6E, 0x67, 0x2E, 0x70, 0x79, 0x00, 0x04, 
+    0x01, 0x00, 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 
+    0x00, 0x00, 0x69, 0x01, 0x00, 0x7C, 0x01, 0x00, 
+    0x83, 0x02, 0x00, 0x53, 0x0A, 0x53, 0x00, 0x02, 
+    0x43, 0x03, 0x02, 0x00, 0x1A, 0x00, 0x04, 0x03, 
+    0x03, 0x05, 0x00, 0x63, 0x6F, 0x75, 0x6E, 0x74, 
+    0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x05, 
+    0x00, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x03, 0x02, 
+    0x00, 0x00, 0x01, 0x03, 0x14, 0x00, 0x2E, 0x2E, 
+    0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 
+    0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x70, 
+    0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, 
+    0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, 
+    0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x0A, 
+    0x51, 0x00, 0x02, 0x43, 0x03, 0x02, 0x00, 0x1D, 
+    0x00, 0x04, 0x03, 0x03, 0x04, 0x00, 0x66, 0x69, 
+    0x6E, 0x64, 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 
+    0x03, 0x04, 0x00, 0x66, 0x69, 0x6E, 0x64, 0x03, 
+    0x02, 0x00, 0x00, 0x01, 0x03, 0x14, 0x00, 0x2E, 
+    0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 
+    0x2F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 
+    0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 
+    0x00, 0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 
+    0x04, 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 
+    0x64, 0x00, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 
+    0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x03, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x04, 0x00, 0x52, 0x53, 0x03, 0x0A, 0x00, 
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+    0x38, 0x39, 0x03, 0x16, 0x00, 0x30, 0x31, 0x32, 
+    0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 
+    0x62, 0x63, 0x64, 0x65, 0x66, 0x41, 0x42, 0x43, 
+    0x44, 0x45, 0x46, 0x03, 0x34, 0x00, 0x61, 0x62, 
+    0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 
+    0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 
+    0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 
+    0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 
+    0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 
+    0x59, 0x5A, 0x0B, 0x02, 0x18, 0x00, 0x0B, 0x02, 
+    0x19, 0x00, 0x0B, 0x02, 0x1A, 0x00, 0x03, 0x01, 
+    0x00, 0x20, 0x0A, 0xBC, 0x00, 0x02, 0x43, 0x03, 
+    0x05, 0x00, 0x01, 0x01, 0x04, 0x02, 0x03, 0x03, 
+    0x00, 0x6C, 0x65, 0x6E, 0x03, 0x04, 0x00, 0x6A, 
+    0x6F, 0x69, 0x6E, 0x03, 0x14, 0x00, 0x00, 0x01, 
+    0x0C, 0x01, 0x0D, 0x01, 0x05, 0x01, 0x0A, 0x01, 
+    0x06, 0x01, 0x03, 0x00, 0x0D, 0x01, 0x12, 0x01, 
+    0x0F, 0x01, 0x03, 0x14, 0x00, 0x2E, 0x2E, 0x2F, 
+    0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x73, 
+    0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x70, 0x79, 
+    0x00, 0x04, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0x00, 0x03, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 
+    0x00, 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 
+    0x00, 0x83, 0x01, 0x00, 0x7D, 0x02, 0x00, 0x7C, 
+    0x02, 0x00, 0x64, 0x01, 0x00, 0x6A, 0x02, 0x00, 
+    0x6F, 0x05, 0x00, 0x01, 0x64, 0x02, 0x00, 0x53, 
+    0x01, 0x7C, 0x00, 0x00, 0x64, 0x01, 0x00, 0x19, 
+    0x7D, 0x03, 0x00, 0x64, 0x03, 0x00, 0x7D, 0x04, 
+    0x00, 0x78, 0x2E, 0x00, 0x7C, 0x04, 0x00, 0x7C, 
+    0x02, 0x00, 0x6A, 0x00, 0x00, 0x6F, 0x20, 0x00, 
+    0x01, 0x7C, 0x03, 0x00, 0x7C, 0x01, 0x00, 0x17, 
+    0x7C, 0x00, 0x00, 0x7C, 0x04, 0x00, 0x19, 0x17, 
+    0x7D, 0x03, 0x00, 0x7C, 0x04, 0x00, 0x64, 0x03, 
+    0x00, 0x37, 0x7D, 0x04, 0x00, 0x71, 0x31, 0x00, 
+    0x01, 0x57, 0x7C, 0x03, 0x00, 0x53, 0x00, 0x04, 
+    0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x5A, 0x00, 
+    0x00, 0x64, 0x01, 0x00, 0x5A, 0x01, 0x00, 0x64, 
+    0x02, 0x00, 0x64, 0x0D, 0x00, 0x64, 0x03, 0x00, 
+    0x84, 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 
+    0x02, 0x00, 0x64, 0x04, 0x00, 0x5A, 0x03, 0x00, 
+    0x64, 0x05, 0x00, 0x5A, 0x04, 0x00, 0x64, 0x06, 
+    0x00, 0x5A, 0x05, 0x00, 0x64, 0x07, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x06, 0x00, 0x64, 0x08, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x07, 0x00, 0x64, 0x09, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x08, 0x00, 0x64, 
+    0x0A, 0x00, 0x64, 0x0B, 0x00, 0x84, 0x01, 0x00, 
+    0x5A, 0x09, 0x00, 0x64, 0x0C, 0x00, 0x53, 
+
+/* ../../lib/sys.py */
+    0x0A, 0x5E, 0x01, 0x00, 0x40, 0x01, 0x00, 0x00, 
+    0x16, 0x00, 0x04, 0x0A, 0x03, 0x06, 0x00, 0x6D, 
+    0x61, 0x78, 0x69, 0x6E, 0x74, 0x03, 0x04, 0x00, 
+    0x65, 0x78, 0x69, 0x74, 0x03, 0x02, 0x00, 0x67, 
+    0x63, 0x03, 0x04, 0x00, 0x67, 0x65, 0x74, 0x62, 
+    0x03, 0x04, 0x00, 0x68, 0x65, 0x61, 0x70, 0x03, 
+    0x04, 0x00, 0x70, 0x75, 0x74, 0x62, 0x03, 0x0B, 
+    0x00, 0x72, 0x75, 0x6E, 0x49, 0x6E, 0x54, 0x68, 
+    0x72, 0x65, 0x61, 0x64, 0x03, 0x04, 0x00, 0x74, 
+    0x69, 0x6D, 0x65, 0x03, 0x04, 0x00, 0x77, 0x61, 
+    0x69, 0x74, 0x03, 0x03, 0x00, 0x73, 0x79, 0x73, 
+    0x03, 0x10, 0x00, 0x06, 0x03, 0x09, 0x23, 0x09, 
+    0x18, 0x09, 0x1A, 0x09, 0x30, 0x09, 0x21, 0x09, 
+    0x1E, 0x09, 0x26, 0x03, 0x11, 0x00, 0x2E, 0x2E, 
+    0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 
+    0x73, 0x79, 0x73, 0x2E, 0x70, 0x79, 0x00, 0x04, 
+    0x0A, 0x01, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0x01, 
+    0x1B, 0x00, 0x0B, 0x00, 0x1C, 0x00, 0x0B, 0x00, 
+    0x1D, 0x00, 0x0B, 0x00, 0x1E, 0x00, 0x0B, 0x01, 
+    0x1F, 0x00, 0x0B, 0x01, 0x20, 0x00, 0x0B, 0x00, 
+    0x21, 0x00, 0x0A, 0x67, 0x00, 0x01, 0x43, 0x02, 
+    0x02, 0x00, 0x03, 0x01, 0x04, 0x02, 0x03, 0x04, 
+    0x00, 0x74, 0x69, 0x6D, 0x65, 0x03, 0x04, 0x00, 
+    0x77, 0x61, 0x69, 0x74, 0x03, 0x08, 0x00, 0x00, 
+    0x01, 0x0D, 0x01, 0x03, 0x00, 0x10, 0x01, 0x03, 
+    0x11, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 
+    0x6C, 0x69, 0x62, 0x2F, 0x73, 0x79, 0x73, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 
+    0x74, 0x00, 0x00, 0x83, 0x00, 0x00, 0x7C, 0x00, 
+    0x00, 0x17, 0x7D, 0x01, 0x00, 0x78, 0x15, 0x00, 
+    0x74, 0x00, 0x00, 0x83, 0x00, 0x00, 0x7C, 0x01, 
+    0x00, 0x6A, 0x00, 0x00, 0x6F, 0x04, 0x00, 0x01, 
+    0x71, 0x10, 0x00, 0x01, 0x57, 0x64, 0x00, 0x00, 
+    0x53, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x5A, 
+    0x00, 0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x01, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x02, 0x00, 0x64, 0x03, 0x00, 0x84, 
+    0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x04, 0x00, 
+    0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, 0x05, 
+    0x00, 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, 0x64, 
+    0x06, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x06, 0x00, 
+    0x64, 0x07, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x07, 
+    0x00, 0x64, 0x08, 0x00, 0x84, 0x00, 0x00, 0x5A, 
+    0x08, 0x00, 0x64, 0x09, 0x00, 0x53, 
+
+/* ../../lib/ipm.py */
+    0x0A, 0x24, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00, 
+    0x11, 0x00, 0x04, 0x04, 0x03, 0x07, 0x00, 0x5F, 
+    0x67, 0x65, 0x74, 0x49, 0x6D, 0x67, 0x03, 0x03, 
+    0x00, 0x78, 0x30, 0x34, 0x03, 0x03, 0x00, 0x69, 
+    0x70, 0x6D, 0x03, 0x03, 0x00, 0x69, 0x70, 0x6D, 
+    0x03, 0x04, 0x00, 0x09, 0x39, 0x09, 0x0B, 0x03, 
+    0x11, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 
+    0x6C, 0x69, 0x62, 0x2F, 0x69, 0x70, 0x6D, 0x2E, 
+    0x70, 0x79, 0x00, 0x04, 0x04, 0x0B, 0x00, 0x22, 
+    0x00, 0x0B, 0x00, 0x23, 0x00, 0x0A, 0xB2, 0x00, 
+    0x01, 0x43, 0x03, 0x04, 0x00, 0x55, 0x00, 0x04, 
+    0x07, 0x03, 0x07, 0x00, 0x5F, 0x67, 0x65, 0x74, 
+    0x49, 0x6D, 0x67, 0x03, 0x02, 0x00, 0x43, 0x6F, 
+    0x03, 0x04, 0x00, 0x65, 0x76, 0x61, 0x6C, 0x03, 
+    0x03, 0x00, 0x78, 0x30, 0x34, 0x03, 0x05, 0x00, 
+    0x46, 0x61, 0x6C, 0x73, 0x65, 0x03, 0x0E, 0x00, 
+    0x41, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6F, 
+    0x6E, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x03, 0x03, 
+    0x00, 0x69, 0x70, 0x6D, 0x03, 0x0C, 0x00, 0x00, 
+    0x01, 0x03, 0x04, 0x09, 0x01, 0x0C, 0x01, 0x0F, 
+    0x01, 0x0A, 0x04, 0x03, 0x11, 0x00, 0x2E, 0x2E, 
+    0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 
+    0x69, 0x70, 0x6D, 0x2E, 0x70, 0x79, 0x00, 0x04, 
+    0x01, 0x00, 0x04, 0x00, 0x78, 0x2E, 0x00, 0x74, 
+    0x00, 0x00, 0x83, 0x00, 0x00, 0x7D, 0x01, 0x00, 
+    0x74, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x83, 0x01, 
+    0x00, 0x7D, 0x02, 0x00, 0x74, 0x02, 0x00, 0x7C, 
+    0x02, 0x00, 0x7C, 0x00, 0x00, 0x83, 0x02, 0x00, 
+    0x7D, 0x03, 0x00, 0x74, 0x03, 0x00, 0x83, 0x00, 
+    0x00, 0x01, 0x71, 0x03, 0x00, 0x74, 0x04, 0x00, 
+    0x70, 0x07, 0x00, 0x01, 0x74, 0x05, 0x00, 0x82, 
+    0x01, 0x00, 0x01, 0x64, 0x00, 0x00, 0x53, 0x00, 
+    0x04, 0x00, 0x64, 0x00, 0x00, 0x84, 0x00, 0x00, 
+    0x5A, 0x00, 0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 
+    0x00, 0x5A, 0x01, 0x00, 0x68, 0x00, 0x00, 0x64, 
+    0x02, 0x00, 0x84, 0x01, 0x00, 0x5A, 0x02, 0x00, 
+    0x64, 0x03, 0x00, 0x53, 
+
+/* img-list-terminator */
+    0xFF, 
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/mbed/pmstdlib_nat.cpp	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,1647 @@
+#undef __FILE_ID__
+#define __FILE_ID__ 0x0A
+/**
+ * PyMite std native function file
+ *
+ * automatically created by pmImgCreator.py
+ * on Sat Mar 02 20:27:03 2013
+ *
+ * DO NOT EDIT THIS FILE.
+ * ANY CHANGES WILL BE LOST.
+ *
+ * @file    pmstdlib_nat.cpp
+ */
+
+#define __IN_LIBNATIVE_C__
+#include "pm.h"
+
+/* From: ../../lib/string.py */
+#include <stdlib.h>
+#include <string.h>
+
+PmReturn_t
+nat_00___bi_chr(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t ps;
+    pPmObj_t pn;
+    int32_t n;
+    PmReturn_t retval;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Raise TypeError if arg is not an int */
+    pn = NATIVE_GET_LOCAL(0);
+    if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Raise ValueError if arg is not int within range(256) */
+    n = ((pPmInt_t)pn)->val;
+    if ((n < 0) || (n > 255))
+    {
+        PM_RAISE(retval, PM_RET_EX_VAL);
+        return retval;
+    }
+
+    /* Create char string from  integer value */
+    retval = string_newFromChar((uint8_t)n, &ps);
+    NATIVE_SET_TOS(ps);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_01___bi_dir(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval = PM_RET_OK;
+    pPmObj_t po;
+    pPmObj_t pk;
+    pPmObj_t pl;
+    pSeglist_t psl;
+    int16_t i;
+    uint8_t objid;
+
+    /* Use globals if no arg given */
+    if (NATIVE_GET_NUM_ARGS() == 0)
+    {
+        /* Get the globals dict */
+        po = (pPmObj_t)NATIVE_GET_PFRAME()->fo_globals;
+    }
+
+    /* Otherwise use the given arg */
+    else if (NATIVE_GET_NUM_ARGS() == 1)
+    {
+        po = NATIVE_GET_LOCAL(0);
+
+        /* If object is a function or module, use its attrs dict */
+        if ((OBJ_GET_TYPE(po) == OBJ_TYPE_FXN)
+            || (OBJ_GET_TYPE(po) == OBJ_TYPE_MOD))
+        {
+            po = (pPmObj_t)((pPmFunc_t)po)->f_attrs;
+        }
+
+#ifdef HAVE_CLASSES
+        else if (OBJ_GET_TYPE(po) == OBJ_TYPE_CLO)
+        {
+            po = (pPmObj_t)((pPmClass_t)po)->cl_attrs;
+        }
+        else if (OBJ_GET_TYPE(po) == OBJ_TYPE_CLI)
+        {
+            po = (pPmObj_t)((pPmInstance_t)po)->cli_attrs;
+        }
+        else if (OBJ_GET_TYPE(po) == OBJ_TYPE_MTH)
+        {
+            po = (pPmObj_t)((pPmMethod_t)po)->m_attrs;
+        }
+#endif /* HAVE_CLASSES */
+
+        else
+        {
+            po = C_NULL;
+        }
+    }
+
+    /* Raise TypeError if wrong number of args */
+    else
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    if (po == C_NULL)
+    {
+        pl = PM_NONE;
+    }
+    else
+    {
+        /* Create new list */
+        retval = list_new(&pl);
+        PM_RETURN_IF_ERROR(retval);
+
+        /* Copy dict's keys to the list */
+        psl = ((pPmDict_t)po)->d_keys;
+        for (i = 0; i < ((pPmDict_t)po)->length; i++)
+        {
+            retval = seglist_getItem(psl, i, &pk);
+            PM_RETURN_IF_ERROR(retval);
+            heap_gcPushTempRoot(pl, &objid);
+            retval = list_append(pl, pk);
+            heap_gcPopTempRoot(objid);
+            PM_RETURN_IF_ERROR(retval);
+        }
+    }
+
+    NATIVE_SET_TOS(pl);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_02___bi_eval(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    pPmObj_t pco;
+    pPmObj_t pfunc;
+    pPmObj_t pnewframe;
+    pPmObj_t pg = C_NULL;
+    pPmObj_t pl = C_NULL;
+    uint8_t objid;
+
+    /* If wrong number of args, raise TypeError */
+    if ((NATIVE_GET_NUM_ARGS() == 0) || (NATIVE_GET_NUM_ARGS() > 3))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Raise ValueError if first arg is not a Code Object */
+    pco = NATIVE_GET_LOCAL(0);
+    if (OBJ_GET_TYPE(pco) != OBJ_TYPE_COB)
+    {
+        PM_RAISE(retval, PM_RET_EX_VAL);
+        return retval;
+    }
+
+    /* If 2nd arg exists, raise ValueError if it is not a Dict */
+    if (NATIVE_GET_NUM_ARGS() >= 2)
+    {
+        pg = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pg) != OBJ_TYPE_DIC)
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+    }
+
+    /* If no args are given, use the caller's globals for the function's */
+    else
+    {
+        pg = (pPmObj_t)NATIVE_GET_PFRAME()->fo_globals;
+    }
+
+    /* If 3rd arg exists, raise ValueError if it is not a Dict */
+    if (NATIVE_GET_NUM_ARGS() >= 3)
+    {
+        pl = NATIVE_GET_LOCAL(2);
+        if (OBJ_GET_TYPE(pl) != OBJ_TYPE_DIC)
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+    }
+
+    /* Create func from code object */
+    retval = func_new(pco, pg, &pfunc);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Create frame from module object; globals is set to null */
+    heap_gcPushTempRoot(pfunc, &objid);
+    retval = frame_new(pfunc, &pnewframe);
+    heap_gcPopTempRoot(objid);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* TODO: Reclaim pnewframe's attrs dict created in frame_new */
+    /*
+     * By default use calling frame's attrs as local namespace.
+     * This works for ipm because the interactive mode
+     * needs a locals namespace that persists across calls to eval()
+     */
+    ((pPmFrame_t)pnewframe)->fo_attrs = NATIVE_GET_PFRAME()->fo_attrs;
+
+    /* If 2nd arg exists, use it as the global namespace for the new func */
+    if (NATIVE_GET_NUM_ARGS() >= 2)
+    {
+        ((pPmFrame_t)pnewframe)->fo_globals = (pPmDict_t)pg;
+
+        /* If only globals is given, locals defaults to it */
+        ((pPmFrame_t)pnewframe)->fo_attrs = (pPmDict_t)pg;
+    }
+
+    /* If 3rd arg exists, use it as the local namespace for the new func */
+    if (NATIVE_GET_NUM_ARGS() >= 3)
+    {
+        ((pPmFrame_t)pnewframe)->fo_attrs = (pPmDict_t)pl;
+    }
+
+    /*
+     * Set the fo_back frame so flow returns to eval()'s caller when completed.
+     * Set the frame pointer so the new frame is interpreted immediately
+     * after this function returns.
+     */
+    ((pPmFrame_t)pnewframe)->fo_back = NATIVE_GET_PFRAME();
+    NATIVE_GET_PFRAME() = (pPmFrame_t)pnewframe;
+    retval = PM_RET_FRAME_SWITCH;
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_03___bi_globals(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pr = C_NULL;
+    PmReturn_t retval;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Return calling frame's globals dict  on stack*/
+    pr = (pPmObj_t)NATIVE_GET_PFRAME()->fo_globals;
+    NATIVE_SET_TOS(pr);
+
+    return PM_RET_OK;
+    
+}
+
+PmReturn_t
+nat_04___bi_id(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    pPmObj_t pr = C_NULL;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Return object's address as an int on the stack */
+    retval = int_new((intptr_t)NATIVE_GET_LOCAL(0), &pr);
+    NATIVE_SET_TOS(pr);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_05___bi_len(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    pPmObj_t ps = C_NULL;
+    pPmObj_t pr = C_NULL;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get first arg */
+    ps = NATIVE_GET_LOCAL(0);
+
+#ifdef HAVE_BYTEARRAY
+    /* If object is an instance, get the thing it contains */
+    if (OBJ_GET_TYPE(ps) == OBJ_TYPE_CLI)
+    {
+        retval = dict_getItem((pPmObj_t)((pPmInstance_t)ps)->cli_attrs,
+                              PM_NONE,
+                              &pr);
+
+        /* If None wasn't in attributes, obj is wrong type for len() */
+        if (retval == PM_RET_EX_KEY) retval = PM_RET_EX_TYPE;
+        PM_RETURN_IF_ERROR(retval);
+        ps = pr;
+    }
+#endif /* HAVE_BYTEARRAY */
+
+    /* Get the length of the arg based on its type */
+    switch (OBJ_GET_TYPE(ps))
+    {
+        case OBJ_TYPE_STR:
+            retval = int_new(((pPmString_t)ps)->length, &pr);
+            break;
+
+        case OBJ_TYPE_TUP:
+            retval = int_new(((pPmTuple_t)ps)->length, &pr);
+            break;
+
+        case OBJ_TYPE_LST:
+            retval = int_new(((pPmList_t)ps)->length, &pr);
+            break;
+
+        case OBJ_TYPE_DIC:
+            retval = int_new(((pPmDict_t)ps)->length, &pr);
+            break;
+
+#ifdef HAVE_BYTEARRAY
+        case OBJ_TYPE_BYA:
+            retval = int_new(((pPmBytearray_t)ps)->length, &pr);
+            break;
+#endif /* HAVE_BYTEARRAY */
+
+        default:
+            /* If not a string or sequence type, raise TypeError */
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+    }
+
+    NATIVE_SET_TOS(pr);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_06___bi_locals(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pr = C_NULL;
+    PmReturn_t retval;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Return calling frame's local attrs dict on the stack */
+    pr = (pPmObj_t)NATIVE_GET_PFRAME()->fo_attrs;
+    NATIVE_SET_TOS(pr);
+
+    return PM_RET_OK;
+    
+}
+
+PmReturn_t
+nat_07___bi_ord(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t ps;
+    pPmObj_t pn;
+    int32_t n;
+    PmReturn_t retval;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    ps = NATIVE_GET_LOCAL(0);
+
+    /* Raise TypeError if arg is not string of length 1 */
+    if ((OBJ_GET_TYPE(ps) != OBJ_TYPE_STR)
+        || (((pPmString_t)ps)->length != 1))
+
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get integer value of character */
+    n = ((pPmString_t)ps)->val[0];
+    retval = int_new(n, &pn);
+    NATIVE_SET_TOS(pn);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_08___bi_range(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    pPmObj_t pa = C_NULL;
+    pPmObj_t pb = C_NULL;
+    pPmObj_t pc = C_NULL;
+    pPmObj_t pi = C_NULL;
+    pPmObj_t pr = C_NULL;
+    int16_t i = 0;
+    uint8_t objid1, objid2;
+
+    switch (NATIVE_GET_NUM_ARGS())
+    {
+        case 1:
+            pa = PM_ZERO;
+            pb = NATIVE_GET_LOCAL(0);
+            pc = PM_ONE;
+            break;
+
+        case 2:
+            pa = NATIVE_GET_LOCAL(0);
+            pb = NATIVE_GET_LOCAL(1);
+            pc = PM_ONE;
+            break;
+
+        case 3:
+            pa = NATIVE_GET_LOCAL(0);
+            pb = NATIVE_GET_LOCAL(1);
+            pc = NATIVE_GET_LOCAL(2);
+
+            /* If 3rd arg is 0, ValueError */
+            if (((pPmInt_t)pc)->val == 0)
+            {
+                PM_RAISE(retval, PM_RET_EX_VAL);
+                return retval;
+            }
+            break;
+
+        default:
+            /* If wrong number of args, raise TypeError */
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+    }
+
+    /* Allocate list */
+    retval = list_new(&pr);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Iterate depending on counting direction */
+    if (((pPmInt_t)pc)->val > 0)
+    {
+        for (i = ((pPmInt_t)pa)->val;
+             i < ((pPmInt_t)pb)->val;
+             i += ((pPmInt_t)pc)->val)
+        {
+            heap_gcPushTempRoot(pr, &objid1);
+            retval = int_new(i, &pi);
+            if (retval != PM_RET_OK)
+            {
+                heap_gcPopTempRoot(objid1);
+                return retval;
+            }
+
+            heap_gcPushTempRoot(pi, &objid2);
+            retval = list_append(pr, pi);
+            heap_gcPopTempRoot(objid1);
+            PM_RETURN_IF_ERROR(retval);
+        }
+    }
+    else
+    {
+        for (i = ((pPmInt_t)pa)->val;
+             i > ((pPmInt_t)pb)->val;
+             i += ((pPmInt_t)pc)->val)
+        {
+            heap_gcPushTempRoot(pr, &objid1);
+            retval = int_new(i, &pi);
+            if (retval != PM_RET_OK)
+            {
+                heap_gcPopTempRoot(objid1);
+                return retval;
+            }
+
+            heap_gcPushTempRoot(pi, &objid2);
+            retval = list_append(pr, pi);
+            heap_gcPopTempRoot(objid1);
+            PM_RETURN_IF_ERROR(retval);
+        }
+    }
+
+    /* Return list */
+    NATIVE_SET_TOS(pr);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_09___bi_sum(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t ps;
+    pPmObj_t pn;
+    pPmObj_t po;
+    int32_t n;
+    uint16_t len;
+    uint16_t i;
+    PmReturn_t retval;
+#ifdef HAVE_FLOAT
+    float f;
+    uint8_t usefloat = C_FALSE;
+#endif /* HAVE_FLOAT */
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    ps = NATIVE_GET_LOCAL(0);
+
+#ifdef HAVE_BYTEARRAY
+    /* Bytearray is a special case to save RAM converting each byte to an Int */
+    if (OBJ_GET_TYPE(ps) == OBJ_TYPE_BYA)
+    {
+        n = 0;
+        len = ((pPmBytearray_t)ps)->length;
+        po = (pPmObj_t)((pPmBytearray_t)ps)->val;
+        for (i = 0; i < len; i++)
+        {
+            n += (uint8_t)((pPmBytes_t)po)->val[i];
+        }
+        retval = int_new(n, &pn);
+        NATIVE_SET_TOS(pn);
+        return retval;
+    }
+#endif /* HAVE_BYTEARRAY */
+
+    /* Raise TypeError if arg is not a sequence */
+    if ((OBJ_GET_TYPE(ps) != OBJ_TYPE_TUP)
+        && (OBJ_GET_TYPE(ps) != OBJ_TYPE_LST)
+        && (OBJ_GET_TYPE(ps) != OBJ_TYPE_DIC))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get the length of the sequence */
+    retval = seq_getLength(ps, &len);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Calculate the sum of the sequence */
+    n = 0;
+#ifdef HAVE_FLOAT
+    f = 0.0;
+#endif
+    for (i = 0; i < len; i++)
+    {
+        retval = seq_getSubscript(ps, i, &po);
+
+        if (OBJ_GET_TYPE(po) == OBJ_TYPE_INT)
+        {
+            /* Add value to sum */
+            n += ((pPmInt_t)po)->val;
+#ifdef HAVE_FLOAT
+            f += (float)((pPmInt_t)po)->val;
+#endif /* HAVE_FLOAT */
+        }
+
+#ifdef HAVE_FLOAT
+        else if (OBJ_GET_TYPE(po) == OBJ_TYPE_FLT)
+        {
+            /* Add value to sum */
+            f += ((pPmFloat_t)po)->val;
+            usefloat = C_TRUE;
+        }
+#endif /* HAVE_FLOAT */
+
+        /* Raise TypeError if item is not an integer */
+        else
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+    }
+
+#ifdef HAVE_FLOAT
+    if (usefloat)
+    {
+        retval = float_new(f, &pn);
+    }
+    else
+#endif /* HAVE_FLOAT */
+    {
+        retval = int_new(n, &pn);
+    }
+    NATIVE_SET_TOS(pn);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_10___bi_type(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    pPmObj_t po = C_NULL;
+    pPmObj_t pr = C_NULL;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get arg */
+    po = NATIVE_GET_LOCAL(0);
+
+    /* Create int from type enum */
+    retval = int_new(OBJ_GET_TYPE(po), &pr);
+    NATIVE_SET_TOS(pr);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_11___bi_Co(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    pPmObj_t pimg;
+    pPmObj_t pco;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Raise ValueError if arg is not an Image Obj */
+    pimg = NATIVE_GET_LOCAL(0);
+    if (OBJ_GET_TYPE(pimg) != OBJ_TYPE_CIO)
+    {
+        PM_RAISE(retval, PM_RET_EX_VAL);
+        return retval;
+    }
+
+    /* Create a code object from the image */
+    retval = obj_loadFromImgObj(pimg, &pco);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Return the code object */
+    NATIVE_SET_TOS(pco);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_12___bi___init__(pPmFrame_t *ppframe)
+{
+
+        PmReturn_t retval;
+        pPmObj_t pself;
+        pPmObj_t pfa;
+        pPmObj_t pfunc;
+        pPmObj_t pframe;
+        uint8_t i;
+        uint8_t objid;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Raise ValueError if first args are not: instance, tuple */
+        pself = NATIVE_GET_LOCAL(0);
+        pfa = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pself) != OBJ_TYPE_CLI)
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+        if (OBJ_GET_TYPE(pfa) != OBJ_TYPE_TUP)
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+
+        /* Create a new frame for the function */
+        pfunc = ((pPmTuple_t)pfa)->val[0];
+        retval = frame_new(pfunc, &pframe);
+        PM_RETURN_IF_ERROR(retval);
+
+        /* Copy args into frame's locals */
+        for (i = 0; i < ((pPmTuple_t)pfa)->length - 1; i++)
+        {
+            /* The pfa tuple is (func, [arg0, ... argN]) */
+            ((pPmFrame_t)pframe)->fo_locals[i] = ((pPmTuple_t)pfa)->val[i + 1];
+        }
+
+        /* Store frame in None attr of instance */
+        heap_gcPushTempRoot(pframe, &objid);
+        retval = dict_setItem((pPmObj_t)((pPmInstance_t)pself)->cli_attrs,
+                              PM_NONE, pframe);
+        heap_gcPopTempRoot(objid);
+
+        NATIVE_SET_TOS(PM_NONE);
+        return retval;
+        
+}
+
+PmReturn_t
+nat_13___bi_send(pPmFrame_t *ppframe)
+{
+
+        PmReturn_t retval;
+        pPmObj_t pself;
+        pPmObj_t parg;
+        pPmObj_t pgenframe;
+
+        /* Raise TypeError if wrong number of args */
+        if (NATIVE_GET_NUM_ARGS() != 2)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        /* Raise ValueError if first arg is not an instance */
+        pself = NATIVE_GET_LOCAL(0);
+        parg = NATIVE_GET_LOCAL(1);
+        if (OBJ_GET_TYPE(pself) != OBJ_TYPE_CLI)
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+
+        /* Get the generator's frame */
+        retval = dict_getItem((pPmObj_t)((pPmInstance_t)pself)->cli_attrs,
+                              PM_NONE, &pgenframe);
+        PM_RETURN_IF_ERROR(retval);
+
+        /* Push argument onto generator's frame's stack */
+        *(((pPmFrame_t)pgenframe)->fo_sp) = parg;
+        ((pPmFrame_t)pgenframe)->fo_sp++;
+
+        /* Set generator's frame's fo_back so yielded value goes to caller */
+        ((pPmFrame_t)pgenframe)->fo_back = NATIVE_GET_PFRAME();
+
+        /* Set active frame to run generator */
+        NATIVE_GET_PFRAME() = (pPmFrame_t)pgenframe;
+
+        return PM_RET_FRAME_SWITCH;
+        
+}
+
+PmReturn_t
+nat_14___bi_ismain(pPmFrame_t *ppframe)
+{
+
+
+    NATIVE_SET_TOS((NATIVE_GET_PFRAME()->fo_isImport) ? PM_FALSE : PM_TRUE);
+
+    return PM_RET_OK;
+    
+}
+
+PmReturn_t
+nat_15_dict_clear(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pd;
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Raise TypeError if it's not a dict or wrong number of args, */
+    pd = NATIVE_GET_LOCAL(0);
+    if ((OBJ_GET_TYPE(pd) != OBJ_TYPE_DIC) || (NATIVE_GET_NUM_ARGS() != 1))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Clear the contents of the dict */
+    retval = dict_clear(pd);
+    PM_RETURN_IF_ERROR(retval);
+
+    NATIVE_SET_TOS(PM_NONE);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_16_dict_keys(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pd;
+    pPmObj_t pl;
+    pPmObj_t pk;
+    pSeglist_t psl;
+    uint16_t i;
+    PmReturn_t retval = PM_RET_OK;
+    uint8_t objid;
+
+    /* Raise TypeError if it's not a dict or wrong number of args, */
+    pd = NATIVE_GET_LOCAL(0);
+    if ((OBJ_GET_TYPE(pd) != OBJ_TYPE_DIC) || (NATIVE_GET_NUM_ARGS() != 1))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Create empty list */
+    retval = list_new(&pl);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Iterate through the keys seglist */
+    psl = ((pPmDict_t)pd)->d_keys;
+    for (i = 0; i < ((pPmDict_t)pd)->length; i++)
+    {
+        /* Get the key and append it to the list */
+        retval = seglist_getItem(psl, i, &pk);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pl, &objid);
+        retval = list_append(pl, pk);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    /* Return the list of keys to the caller */
+    NATIVE_SET_TOS(pl);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_17_dict_values(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pd;
+    pPmObj_t pl;
+    pPmObj_t pv;
+    pSeglist_t psl;
+    uint16_t i;
+    PmReturn_t retval = PM_RET_OK;
+    uint8_t objid;
+
+    /* Raise TypeError if it's not a dict or wrong number of args, */
+    pd = NATIVE_GET_LOCAL(0);
+    if ((OBJ_GET_TYPE(pd) != OBJ_TYPE_DIC) || (NATIVE_GET_NUM_ARGS() != 1))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Create empty list */
+    retval = list_new(&pl);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Iterate through the values seglist */
+    psl = ((pPmDict_t)pd)->d_vals;
+    for (i = 0; i < ((pPmDict_t)pd)->length; i++)
+    {
+        /* Get the value and append it to the list */
+        retval = seglist_getItem(psl, i, &pv);
+        PM_RETURN_IF_ERROR(retval);
+        heap_gcPushTempRoot(pl, &objid);
+        retval = list_append(pl, pv);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    /* Return the list of values to the caller */
+    NATIVE_SET_TOS(pl);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_18_dict_update(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pd1;
+    pPmObj_t pd2;
+    PmReturn_t retval;
+
+    /* Raise TypeError if wrong number of args, */
+    if (NATIVE_GET_NUM_ARGS() != 2)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    pd1 = NATIVE_GET_LOCAL(0);
+    pd2 = NATIVE_GET_LOCAL(1);
+    retval = dict_update(pd1, pd2, C_FALSE);
+
+    NATIVE_SET_TOS(PM_NONE);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_19_list_append(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pl;
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Raise TypeError if it's not a list or wrong number of args, */
+    pl = NATIVE_GET_LOCAL(0);
+    if ((OBJ_GET_TYPE(pl) != OBJ_TYPE_LST) || (NATIVE_GET_NUM_ARGS() != 2))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Append the object to the list */
+    retval = list_append(pl, NATIVE_GET_LOCAL(1));
+
+    NATIVE_SET_TOS(PM_NONE);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_20_list_index(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pl;
+    pPmObj_t po;
+    pPmObj_t pi;
+    PmReturn_t retval = PM_RET_OK;
+    uint16_t i;
+
+    /* Raise TypeError if it's not a list or wrong number of args, */
+    pl = NATIVE_GET_LOCAL(0);
+    if ((OBJ_GET_TYPE(pl) != OBJ_TYPE_LST) || (NATIVE_GET_NUM_ARGS() != 2))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get the index of the object in the list */
+    po = NATIVE_GET_LOCAL(1);
+    retval = list_index(pl, po, &i);
+
+    if (retval == PM_RET_EX_VAL)
+    {
+        PM_RAISE(retval, PM_RET_EX_VAL);
+        return retval;
+    }
+
+    int_new((int32_t)i, &pi);
+    NATIVE_SET_TOS(pi);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_21_list_insert(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pl;
+    pPmObj_t pi;
+    pPmObj_t po;
+    PmReturn_t retval = PM_RET_OK;
+    uint16_t i;
+
+    /*
+     * Raise TypeError if wrong number of args, first arg is not a list, or
+     * second arg is not an int
+     */
+    pl = NATIVE_GET_LOCAL(0);
+    pi = NATIVE_GET_LOCAL(1);
+    po = NATIVE_GET_LOCAL(2);
+    if ((NATIVE_GET_NUM_ARGS() != 3)
+        || (OBJ_GET_TYPE(pl) != OBJ_TYPE_LST)
+        || (OBJ_GET_TYPE(pi) != OBJ_TYPE_INT) )
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Insert the object before the given index */
+    i = (uint16_t)((pPmInt_t)pi)->val;
+    retval = list_insert(pl, i, po);
+
+    if (retval != PM_RET_OK)
+    {
+        PM_RAISE(retval, PM_RET_EX_SYS);
+    }
+
+    NATIVE_SET_TOS(PM_NONE);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_22_list_pop(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pl;
+    pPmObj_t pi;
+    pPmObj_t po;
+    PmReturn_t retval = PM_RET_OK;
+    int16_t i;
+
+    /*
+     * Raise TypeError if first arg is not a list o second arg is not an int
+     * or there are the wrong number of arguments
+     */
+    pl = NATIVE_GET_LOCAL(0);
+    if (OBJ_GET_TYPE(pl) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    pi = NATIVE_GET_LOCAL(1);
+    if (NATIVE_GET_NUM_ARGS() == 2)
+    {
+        if (OBJ_GET_TYPE(pi) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+        i = (uint16_t)((pPmInt_t)pi)->val;
+    }
+    else
+    {
+        i = -1;
+    }
+    if ((NATIVE_GET_NUM_ARGS() < 1) || (NATIVE_GET_NUM_ARGS() > 2))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get the object at the given index */
+    retval = list_getItem(pl, i, &po);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Return the object to the caller */
+    NATIVE_SET_TOS(po);
+
+    /* Remove the object from the given index */
+    retval = list_delItem(pl, i);
+    PM_RETURN_IF_ERROR(retval);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_23_list_remove(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pl;
+    pPmObj_t pv;
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Raise TypeError if it's not a list or wrong number of args, */
+    pl = NATIVE_GET_LOCAL(0);
+    if ((OBJ_GET_TYPE(pl) != OBJ_TYPE_LST) || (NATIVE_GET_NUM_ARGS() != 2))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Remove the value from the list */
+    pv = NATIVE_GET_LOCAL(1);
+    retval = list_remove(pl, pv);
+    if (retval != PM_RET_OK)
+    {
+        PM_RAISE(retval, retval);
+    }
+
+    NATIVE_SET_TOS(PM_NONE);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_24_string_atoi(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pa;
+    pPmObj_t pb;
+    char const *pc;
+    char *pend;
+    long i;
+    int8_t base;
+    pPmObj_t pi;
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Raise TypeError if it's not a string or wrong number of args, */
+    pa = NATIVE_GET_LOCAL(0);
+    if ((OBJ_GET_TYPE(pa) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() < 1)
+        || (NATIVE_GET_NUM_ARGS() > 2))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get the base, if it exists; otherwise assume 10 */
+    base = 10;
+    if (NATIVE_GET_NUM_ARGS() == 2)
+    {
+        pb = NATIVE_GET_LOCAL(1);
+
+        /* Raise a TypeError if 2nd arg is not an int */
+        if (OBJ_GET_TYPE(pb) != OBJ_TYPE_INT)
+        {
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+        }
+
+        base = ((pPmInt_t)pb)->val;
+
+        /* Raise ValueError if base is out of range */
+        if ((base < 0) || (base == 1) || (base > 36))
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+    }
+
+    /* Perform conversion */
+    pend = C_NULL;
+    pc = (char const *)&(((pPmString_t)pa)->val);
+    i = strtol(pc, &pend, base);
+
+    /* Raise ValueError if there was a conversion error */
+    if (*pend != C_NULL)
+    {
+        PM_RAISE(retval, PM_RET_EX_VAL);
+        return retval;
+    }
+
+    /* Create an int object to hold the result of the conversion */
+    retval = int_new(i, &pi);
+
+    NATIVE_SET_TOS(pi);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_25_string_count(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t ps1;
+    pPmObj_t ps2;
+    uint8_t *pc1;
+    uint8_t *pc2;
+    uint8_t *pscan;
+    uint8_t *pmatch;
+    uint8_t pc2c0;
+    uint16_t pc1len;
+    uint16_t pc2len;
+    uint16_t n;
+    uint16_t remaining;
+    uint16_t cmp;
+    pPmObj_t pn;
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Raise TypeError if it's not a string or wrong number of args, */
+    ps1 = NATIVE_GET_LOCAL(0);
+    ps2 = NATIVE_GET_LOCAL(1);
+    if ((OBJ_GET_TYPE(ps1) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() != 2)
+        || (OBJ_GET_TYPE(ps2) != OBJ_TYPE_STR))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    pc1 = ((pPmString_t)ps1)->val;
+    pc2 = ((pPmString_t)ps2)->val;
+    pc1len = ((pPmString_t)ps1)->length;
+    pc2len = ((pPmString_t)ps2)->length;
+    n = 0;
+
+    /* Handle some quick special cases (order of if-clauses is important) */
+    if (pc2len == 0)
+    {
+        n = pc1len + 1;
+    }
+    else if (pc1len == 0)
+    {
+        n = 0;
+    }
+
+    /* Count the number of matches */
+    else
+    {
+        n = 0;
+        remaining = pc1len;
+        pscan = pc1;
+        pc2c0 = pc2[0];
+        while (pscan <= (pc1 + (pc1len - pc2len)))
+        {
+            /* Find the next possible start */
+            pmatch = (uint8_t *)memchr(pscan, pc2c0, remaining);
+            if (pmatch == C_NULL) break;
+            remaining -= (pmatch - pscan);
+            pscan = pmatch;
+
+            /* If it matches, increase the count, else try the next char */
+            cmp = memcmp(pscan, pc2, pc2len);
+            if (cmp == 0)
+            {
+                n++;
+                pscan += pc2len;
+                remaining -= pc2len;
+            }
+            else
+            {
+                pscan++;
+                remaining--;
+            }
+        }
+    }
+
+    retval = int_new(n, &pn);
+
+    NATIVE_SET_TOS(pn);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_26_string_find(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t ps1;
+    pPmObj_t ps2;
+    uint8_t *pc1;
+    uint8_t *pc2;
+    uint8_t *pmatch;
+    uint16_t pc1len;
+    uint16_t pc2len;
+    int32_t n;
+    pPmObj_t pn;
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Raise TypeError if it's not a string or wrong number of args, */
+    ps1 = NATIVE_GET_LOCAL(0);
+    ps2 = NATIVE_GET_LOCAL(1);
+    if ((OBJ_GET_TYPE(ps1) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() != 2)
+        || (OBJ_GET_TYPE(ps2) != OBJ_TYPE_STR))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    pc1 = ((pPmString_t)ps1)->val;
+    pc2 = ((pPmString_t)ps2)->val;
+    pc1len = ((pPmString_t)ps1)->length;
+    pc2len = ((pPmString_t)ps2)->length;
+    n = -1;
+
+    /* Handle a quick special case */
+    if (pc2len == 0)
+    {
+        n = 0;
+    }
+
+    /* Try to find the index of the substring */
+    else
+    {
+        /* Find the next possible start */
+        pmatch = (uint8_t *)memchr(pc1, pc2[0], pc1len);
+        if (pmatch != C_NULL)
+        {
+            /* If it matches, calculate the index */
+            if (memcmp(pmatch, pc2, pc2len) == 0)
+            {
+                n = pmatch - pc1;
+            }
+        }
+    }
+
+    retval = int_new(n, &pn);
+
+    NATIVE_SET_TOS(pn);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_27_sys_exit(pPmFrame_t *ppframe)
+{
+
+    pPmObj_t pval = C_NULL;
+    PmReturn_t retval;
+
+    /* If no arg given, assume return 0 */
+    if (NATIVE_GET_NUM_ARGS() == 0)
+    {
+        NATIVE_SET_TOS(PM_ZERO);
+    }
+
+    /* If 1 arg given, put it on stack */
+    else if (NATIVE_GET_NUM_ARGS() == 1)
+    {
+        pval = NATIVE_GET_LOCAL(0);
+        NATIVE_SET_TOS(pval);
+    }
+
+    /* If wrong number of args, raise TypeError */
+    else
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Raise the SystemExit exception */
+    PM_RAISE(retval, PM_RET_EX_EXIT);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_28_sys_gc(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval = PM_RET_OK;
+#ifdef HAVE_GC
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    retval = heap_gcRun();
+#endif
+    NATIVE_SET_TOS(PM_NONE);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_29_sys_getb(pPmFrame_t *ppframe)
+{
+
+    uint8_t b;
+    pPmObj_t pb;
+    PmReturn_t retval;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    retval = plat_getByte(&b);
+    PM_RETURN_IF_ERROR(retval);
+
+    retval = int_new((int32_t)b, &pb);
+    NATIVE_SET_TOS(pb);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_30_sys_heap(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    pPmObj_t pavail;
+    pPmObj_t psize;
+    pPmObj_t ptup;
+    uint8_t objid;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Allocate a tuple to store the return values */
+    retval = tuple_new(2, &ptup);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Get the maximum heap size */
+    heap_gcPushTempRoot(ptup, &objid);
+    retval = int_new(heap_getSize(), &psize);
+    if (retval != PM_RET_OK)
+    {
+        heap_gcPopTempRoot(objid);
+        return retval;
+    }
+
+    /* Allocate an int to hold the amount of heap available */
+    retval = int_new(heap_getAvail() - sizeof(PmInt_t), &pavail);
+    heap_gcPopTempRoot(objid);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Put the two heap values in the tuple */
+    ((pPmTuple_t)ptup)->val[0] = pavail;
+    ((pPmTuple_t)ptup)->val[1] = psize;
+
+    /* Return the tuple on the stack */
+    NATIVE_SET_TOS(ptup);
+
+    return retval;
+    
+}
+
+PmReturn_t
+nat_31_sys_putb(pPmFrame_t *ppframe)
+{
+
+    uint8_t b;
+    pPmObj_t pb;
+    PmReturn_t retval;
+
+    pb = NATIVE_GET_LOCAL(0);
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* If arg is not an int, raise TypeError */
+    if (OBJ_GET_TYPE(pb) != OBJ_TYPE_INT)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    b = ((pPmInt_t)pb)->val & 0xFF;
+    retval = plat_putByte(b);
+    NATIVE_SET_TOS(PM_NONE);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_32_sys_runInThread(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    pPmObj_t pf;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 1)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* If arg is not a function, raise TypeError */
+    pf = NATIVE_GET_LOCAL(0);
+    if (OBJ_GET_TYPE(pf) != OBJ_TYPE_FXN)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    retval = interp_addThread((pPmFunc_t)pf);
+    NATIVE_SET_TOS(PM_NONE);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_33_sys_time(pPmFrame_t *ppframe)
+{
+
+    uint32_t t;
+    pPmObj_t pt;
+    PmReturn_t retval;
+
+    /* If wrong number of args, raise TypeError */
+    if (NATIVE_GET_NUM_ARGS() != 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get the system time (milliseconds since init) */
+    retval = plat_getMsTicks(&t);
+    PM_RETURN_IF_ERROR(retval);
+
+    /*
+     * Raise ValueError if there is an overflow
+     * (plat_getMsTicks is unsigned; int is signed)
+     */
+    if ((int32_t)t < 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_VAL);
+        return retval;
+    }
+
+    /* Return an int object with the time value */
+    retval = int_new((int32_t)t, &pt);
+    NATIVE_SET_TOS(pt);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_34_ipm__getImg(pPmFrame_t *ppframe)
+{
+
+    PmReturn_t retval;
+    uint8_t imgType;
+    uint16_t imgSize;
+    uint8_t *pchunk;
+    pPmCodeImgObj_t pimg;
+    uint16_t i;
+    uint8_t b;
+
+    /* Get the image type */
+    retval = plat_getByte(&imgType);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Quit if a code image type was not received */
+    if (imgType != OBJ_TYPE_CIM)
+    {
+        PM_RAISE(retval, PM_RET_EX_STOP);
+        return retval;
+    }
+
+    /* Get the image size (little endien) */
+    retval = plat_getByte(&b);
+    PM_RETURN_IF_ERROR(retval);
+    imgSize = b;
+    retval = plat_getByte(&b);
+    PM_RETURN_IF_ERROR(retval);
+    imgSize |= (b << 8);
+
+    /* Get space for CodeImgObj */
+    retval = heap_getChunk(sizeof(PmCodeImgObj_t) + imgSize, &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pimg = (pPmCodeImgObj_t)pchunk;
+    OBJ_SET_TYPE(pimg, OBJ_TYPE_CIO);
+
+    /* Start the image with the bytes that have already been received */
+    i = 0;
+    pimg->val[i++] = imgType;
+    pimg->val[i++] = imgSize & 0xFF;
+    pimg->val[i++] = (imgSize >> 8) & 0xFF;
+
+    /* Get the remaining bytes in the image */
+    for(; i < imgSize; i++)
+    {
+        retval = plat_getByte(&b);
+        PM_RETURN_IF_ERROR(retval);
+
+        pimg->val[i] = b;
+    }
+
+    /* Return the image as a code image object on the stack */
+    NATIVE_SET_TOS((pPmObj_t)pimg);
+    return retval;
+    
+}
+
+PmReturn_t
+nat_35_ipm_x04(pPmFrame_t *ppframe)
+{
+
+    NATIVE_SET_TOS(PM_NONE);
+    return plat_putByte(0x04);
+    
+}
+
+/* Native function lookup table */
+pPmNativeFxn_t const std_nat_fxn_table[] =
+{
+    nat_00___bi_chr,
+    nat_01___bi_dir,
+    nat_02___bi_eval,
+    nat_03___bi_globals,
+    nat_04___bi_id,
+    nat_05___bi_len,
+    nat_06___bi_locals,
+    nat_07___bi_ord,
+    nat_08___bi_range,
+    nat_09___bi_sum,
+    nat_10___bi_type,
+    nat_11___bi_Co,
+    nat_12___bi___init__,
+    nat_13___bi_send,
+    nat_14___bi_ismain,
+    nat_15_dict_clear,
+    nat_16_dict_keys,
+    nat_17_dict_values,
+    nat_18_dict_update,
+    nat_19_list_append,
+    nat_20_list_index,
+    nat_21_list_insert,
+    nat_22_list_pop,
+    nat_23_list_remove,
+    nat_24_string_atoi,
+    nat_25_string_count,
+    nat_26_string_find,
+    nat_27_sys_exit,
+    nat_28_sys_gc,
+    nat_29_sys_getb,
+    nat_30_sys_heap,
+    nat_31_sys_putb,
+    nat_32_sys_runInThread,
+    nat_33_sys_time,
+    nat_34_ipm__getImg,
+    nat_35_ipm_x04,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/bytearray.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,267 @@
+/*
+# This file is Copyright 2010 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x19
+
+
+/**
+ * \file
+ * \brief VM Bytearray Type
+ *
+ * VM Bytearray object type operations.
+ */
+
+#include "pm.h"
+#ifdef HAVE_BYTEARRAY
+
+
+#define ROUND_UP_TO_MUL_OF_FOUR(n) n = (((n) + 3) & ~3)
+
+
+/* Returns a container that can hold at least n bytes */
+static
+PmReturn_t
+bytes_new(int16_t n, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmBytes_t pb = C_NULL;
+
+    ROUND_UP_TO_MUL_OF_FOUR(n);
+
+    /* Allocate a container */
+    retval = heap_getChunk(sizeof(PmBytes_t) + n, (uint8_t **)&pb);
+    PM_RETURN_IF_ERROR(retval);
+    OBJ_SET_TYPE(pb, OBJ_TYPE_BYS);
+    pb->length = n;
+
+    *r_pobj = (pPmObj_t)pb;
+    return retval;
+}
+
+
+/* Returns the int or one-char string as a byte */
+static
+PmReturn_t
+bytes_getByteFromObj(pPmObj_t pobj, uint8_t *b)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_INT)
+    {
+        if ((((pPmInt_t)pobj)->val > 255) || (((pPmInt_t)pobj)->val < 0))
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+
+        *b = (uint8_t)((pPmInt_t)pobj)->val;
+    }
+
+    else if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_STR)
+    {
+        if (((pPmString_t)pobj)->length != 1)
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+        *b = ((pPmString_t)pobj)->val[0];
+    }
+
+    else
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+    }
+    return retval;
+}
+
+
+PmReturn_t
+bytearray_new(pPmObj_t pobj, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmBytearray_t pba = C_NULL;
+    pPmBytes_t pb = C_NULL;
+    pPmObj_t pitem;
+    int32_t i;
+    int16_t n;
+    uint8_t b;
+    uint8_t objid;
+
+    /* If object is an instance, get the thing it is containing */
+    if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_CLI)
+    {
+        retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs,
+                              PM_NONE,
+                              (pPmObj_t *)&pba);
+        PM_RETURN_IF_ERROR(retval);
+        pobj = (pPmObj_t)pba;
+    }
+
+    /* Get the requested length of the new bytearray */
+    switch (OBJ_GET_TYPE(pobj))
+    {
+        case OBJ_TYPE_INT:
+            i = ((pPmInt_t)pobj)->val;
+            if ((i < 0) || (i > 65535))
+            {
+                PM_RAISE(retval, PM_RET_EX_VAL);
+                return retval;
+            }
+            n = i;
+            break;
+
+        case OBJ_TYPE_STR:
+            n = ((pPmString_t)pobj)->length;
+            break;
+
+        case OBJ_TYPE_LST:
+            n = ((pPmList_t)pobj)->length;
+            break;
+
+        case OBJ_TYPE_TUP:
+            n = ((pPmTuple_t)pobj)->length;
+            break;
+
+        case OBJ_TYPE_BYA:
+            n = ((pPmBytearray_t)pobj)->length;
+            break;
+
+        default:
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            return retval;
+    }
+
+    /* Allocate a bytearray */
+    retval = heap_getChunk(sizeof(PmBytearray_t), (uint8_t **)&pba);
+    PM_RETURN_IF_ERROR(retval);
+    OBJ_SET_TYPE(pba, OBJ_TYPE_BYA);
+    pba->length = n;
+    pba->val = C_NULL;
+
+    /* Allocate the bytes container */
+    heap_gcPushTempRoot((pPmObj_t)pba, &objid);
+    retval = bytes_new(n, (pPmObj_t *)&pb);
+    heap_gcPopTempRoot(objid);
+    PM_RETURN_IF_ERROR(retval);
+    pba->val = pb;
+
+    /* Fill the bytes */
+    switch (OBJ_GET_TYPE(pobj))
+    {
+        case OBJ_TYPE_INT:
+            sli_memset((unsigned char *)&(pb->val), '\0', n);
+            break;
+
+        case OBJ_TYPE_BYA:
+            pitem = (pPmObj_t)((pPmBytearray_t)pobj)->val;
+            sli_memcpy(&(pb->val[0]), &(((pPmBytes_t)pitem)->val[0]), n);
+            break;
+
+        case OBJ_TYPE_STR:
+            sli_memcpy(&(pb->val[0]), &(((pPmString_t)pobj)->val[0]), n);
+            break;
+
+        case OBJ_TYPE_LST:
+        case OBJ_TYPE_TUP:
+            for (i = 0; i < n; i++)
+            {
+                retval = seq_getSubscript(pobj, i, &pitem);
+                PM_RETURN_IF_ERROR(retval);
+                retval = bytes_getByteFromObj(pitem, &b);
+                PM_RETURN_IF_ERROR(retval);
+                pb->val[i] = b;
+            }
+            break;
+    }
+
+    *r_pobj = (pPmObj_t)pba;
+    return retval;
+}
+
+
+PmReturn_t
+bytearray_getItem(pPmObj_t pobj, int16_t index, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmBytearray_t pba;
+    pPmBytes_t pb;
+    int32_t n;
+
+    pba = (pPmBytearray_t)pobj;
+
+    /* Adjust a negative index */
+    if (index < 0)
+    {
+        index += pba->length;
+    }
+
+    /* Check the bounds of the index */
+    if ((index < 0) || (index >= pba->length))
+    {
+        PM_RAISE(retval, PM_RET_EX_INDX);
+        return retval;
+    }
+
+    /* Create int from byte at index */
+    pb = pba->val;
+    n = (int32_t)pb->val[index];
+    retval = int_new(n, r_pobj);
+
+    return retval;
+}
+
+
+PmReturn_t
+bytearray_setItem(pPmObj_t pba, int16_t index, pPmObj_t pobj)
+{
+    PmReturn_t retval;
+    pPmBytes_t pb;
+    uint8_t b = 0;
+
+    /* Adjust a negative index */
+    if (index < 0)
+    {
+        index += ((pPmBytearray_t)pba)->length;
+    }
+
+    /* Check the bounds of the index */
+    if ((index < 0) || (index >= ((pPmBytearray_t)pba)->length))
+    {
+        PM_RAISE(retval, PM_RET_EX_INDX);
+        return retval;
+    }
+
+    /* Set the item */
+    retval = bytes_getByteFromObj(pobj, &b);
+    pb = ((pPmBytearray_t)pba)->val;
+    pb->val[index] = b;
+
+    return retval;
+}
+
+
+#ifdef HAVE_PRINT
+PmReturn_t
+bytearray_print(pPmObj_t pobj)
+{
+    PmReturn_t retval;
+    pPmBytes_t pb;
+
+    obj_print(PM_BYTEARRAY_STR, C_FALSE, C_FALSE);
+    plat_putByte('(');
+    plat_putByte('b');
+    pb = ((pPmBytearray_t)pobj)->val;
+    retval = string_printFormattedBytes(&(pb->val[0]),
+                                        C_TRUE,
+                                        ((pPmBytearray_t)pobj)->length);
+    plat_putByte(')');
+    return retval;
+}
+#endif /* HAVE_PRINT */
+#endif /* HAVE_BYTEARRAY */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/bytearray.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,63 @@
+/*
+# This file is Copyright 2010 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __BYTEARRAY_H__
+#define __BYTEARRAY_H__
+
+/**
+ * \file
+ * \brief Bytearray Object Type
+ *
+ * Bytearray object type header.
+ */
+
+
+/**
+ * Bytes container
+ *
+ * Holds actual byte payload
+ */
+typedef struct PmBytes_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Physical number of bytes in the C array (below) */
+    uint16_t length;
+
+    /** C array of bytes */
+    uint8_t val[1];
+} PmBytes_t,
+ *pPmBytes_t;
+
+
+/**
+ * Bytearray obj
+ *
+ * Mutable ordered sequence of bytes.  Contains ptr to chunk of bytes.
+ */
+typedef struct PmBytearray_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Bytearray length; logical number of bytes */
+    uint16_t length;
+
+    /** Ptr to bytes container (may hold more bytes than length) */
+    pPmBytes_t val;
+} PmBytearray_t,
+ *pPmBytearray_t;
+
+ 
+PmReturn_t bytearray_new(pPmObj_t pobj, pPmObj_t *r_pobj);
+PmReturn_t bytearray_getItem(pPmObj_t pobj, int16_t index, pPmObj_t *r_pobj);
+PmReturn_t bytearray_setItem(pPmObj_t pba, int16_t index, pPmObj_t pobj);
+PmReturn_t bytearray_print(pPmObj_t pobj);
+
+#endif /* __BYTEARRAY_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/class.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,268 @@
+/*
+# This file is Copyright 2009 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x18
+
+
+/**
+ * \file
+ * \brief Class Object Type
+ *
+ * Class object type operations.
+ */
+
+
+#include "pm.h"
+
+
+#ifdef HAVE_AUTOBOX
+static uint8_t const *liststr = (uint8_t const *)"list";
+static uint8_t const *dictstr = (uint8_t const *)"dict";
+static uint8_t const *stringstr = (uint8_t const *)"string";
+static uint8_t const *autoboxstr = (uint8_t const *)"_Autobox";
+static uint8_t const *objstr = (uint8_t const *)"obj";
+#endif
+
+
+PmReturn_t
+class_new(pPmObj_t pattrs, pPmObj_t pbases, pPmObj_t pname, pPmObj_t *r_pclass)
+{
+    PmReturn_t retval = PM_RET_OK;
+    uint8_t *pchunk;
+    pPmObj_t pobj;
+
+    /* Ensure types */
+    if ((OBJ_GET_TYPE(pattrs) != OBJ_TYPE_DIC)
+        || (OBJ_GET_TYPE(pbases) != OBJ_TYPE_TUP)
+        || (OBJ_GET_TYPE(pname) != OBJ_TYPE_STR))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Allocate a class obj */
+    retval = heap_getChunk(sizeof(PmClass_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pobj = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(pobj, OBJ_TYPE_CLO);
+
+    /* Class has no access to its CO */
+    ((pPmClass_t)pobj)->cl_attrs = (pPmDict_t)pattrs;
+    ((pPmClass_t)pobj)->cl_bases = (pPmTuple_t)pbases;
+
+    *r_pclass = pobj;
+
+    return retval;
+}
+
+
+/* Returns an instance of the class by reference */
+PmReturn_t
+class_instantiate(pPmObj_t pclass, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    uint8_t *pchunk;
+    pPmObj_t pobj;
+    pPmObj_t pattrs;
+    uint8_t objid;
+
+    /* Allocate a class instance */
+    retval = heap_getChunk(sizeof(PmInstance_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pobj = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(pobj, OBJ_TYPE_CLI);
+
+    /* Set the instance's fields */
+    ((pPmInstance_t)pobj)->cli_class = (pPmClass_t)pclass;
+    ((pPmInstance_t)pobj)->cli_attrs = C_NULL;
+
+    /* Create the attributes dict */
+    heap_gcPushTempRoot(pobj, &objid);
+    retval = dict_new(&pattrs);
+    heap_gcPopTempRoot(objid);
+    ((pPmInstance_t)pobj)->cli_attrs = (pPmDict_t)pattrs;
+
+    /* TODO: Store pclass in __class__ attr */
+
+    *r_pobj = pobj;
+    return retval;
+}
+
+
+#ifdef HAVE_AUTOBOX
+PmReturn_t
+class_autobox(pPmObj_t *pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmObj_t pmodule, pstr, pclass, pwrapped, pmodcache;
+
+    uint8_t const *pliststr = liststr;
+    uint8_t const *pdictstr = dictstr;
+    uint8_t const *pstringstr = stringstr;
+
+    uint8_t const *pAutoboxstr = autoboxstr;
+    uint8_t const *pobjstr = objstr;
+
+    /* Load the appropriate module name,
+     * or do nothing if we have a non-boxable type
+     */
+    if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_LST) {
+        retval = string_new(&pliststr, &pstr);
+        PM_RETURN_IF_ERROR(retval);
+    } else if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_DIC) {
+        retval = string_new(&pdictstr, &pstr);
+        PM_RETURN_IF_ERROR(retval);
+    } else if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_STR) {
+        retval = string_new(&pstringstr, &pstr);
+        PM_RETURN_IF_ERROR(retval);
+    } else {
+        return retval;
+    }
+
+    /** first, try to get the module from the cache */
+    retval = dict_getItem(PM_PBUILTINS, PM_MD_STR, &pmodcache);
+    PM_RETURN_IF_ERROR(retval);
+
+    retval = dict_getItem(pmodcache, pstr, &pmodule);
+    PM_RETURN_IF_ERROR(retval);
+
+    if (!((retval == PM_RET_OK) && (OBJ_GET_TYPE(pmodule) == OBJ_TYPE_MOD)))
+    {
+        PM_RAISE(retval, PM_RET_EX_SYS);
+        return retval;
+    }
+
+    /* grab the class from within the loaded module */
+    retval = string_new(&pAutoboxstr, &pstr);
+    PM_RETURN_IF_ERROR(retval);
+    retval = dict_getItem((pPmObj_t) ((pPmFunc_t)pmodule)->f_attrs, pstr, &pclass);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* instantiate instance of (type)._Autobox */
+    retval = class_instantiate(pclass, &pwrapped);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* store object as _Autobox().obj */
+    retval = string_new(&pobjstr, &pstr);
+    PM_RETURN_IF_ERROR(retval);
+    retval = dict_setItem((pPmObj_t)((pPmInstance_t)pwrapped)->cli_attrs,
+                          pstr, *pobj);
+    PM_RETURN_IF_ERROR(retval);
+
+    /** replace old object with new instance in place */
+    *pobj = pwrapped;
+
+    return retval;
+}
+#endif
+
+
+PmReturn_t
+class_method(pPmObj_t pinstance, pPmObj_t pfunc, pPmObj_t *r_pmeth)
+{
+    PmReturn_t retval = PM_RET_OK;
+    uint8_t *pchunk;
+    pPmMethod_t pmeth;
+    pPmObj_t pattrs;
+    uint8_t objid;
+
+    /* Allocate a method */
+    retval = heap_getChunk(sizeof(PmMethod_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    OBJ_SET_TYPE(pchunk, OBJ_TYPE_MTH);
+
+    /* Set method fields */
+    pmeth = (pPmMethod_t)pchunk;
+    pmeth->m_instance = (pPmInstance_t)pinstance;
+    pmeth->m_func = (pPmFunc_t)pfunc;
+    pmeth->m_attrs = C_NULL;
+
+    /* Create the attributes dict */
+    heap_gcPushTempRoot((pPmObj_t)pmeth, &objid);
+    retval = dict_new(&pattrs);
+    heap_gcPopTempRoot(objid);
+    pmeth->m_attrs = (pPmDict_t)pattrs;
+
+    *r_pmeth = (pPmObj_t)pmeth;
+    return retval;
+}
+
+
+PmReturn_t
+class_getAttr(pPmObj_t pobj, pPmObj_t pname, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval;
+    uint16_t i;
+    pPmObj_t pparent;
+
+    /* If the given obj is an instance, check its attrs */
+    if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_CLI)
+    {
+        retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs, pname,
+                              r_pobj);
+        if (retval == PM_RET_OK)
+        {
+            return retval;
+        }
+
+        /* Otherwise, check the instance's class */
+        pobj = (pPmObj_t)((pPmInstance_t)pobj)->cli_class;
+    }
+
+    C_ASSERT(OBJ_GET_TYPE(pobj) == OBJ_TYPE_CLO);
+
+    retval = dict_getItem((pPmObj_t)((pPmClass_t)pobj)->cl_attrs, pname,
+                          r_pobj);
+
+    /* If attr is not found, search parent(s) */
+    if ((retval == PM_RET_EX_KEY) && (((pPmClass_t)pobj)->cl_bases != C_NULL))
+    {
+        for (i = 0; i < ((pPmClass_t)pobj)->cl_bases->length; i++)
+        {
+            pparent = ((pPmClass_t)pobj)->cl_bases->val[i];
+            retval = class_getAttr(pparent, pname, r_pobj);
+            if (retval == PM_RET_OK)
+            {
+                break;
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+uint8_t /* boolean */
+class_isSubclass(pPmObj_t ptest_class, pPmObj_t pbase_class)
+{
+    uint8_t i;
+    uint8_t retval;
+
+    retval = C_FALSE;
+
+    if (ptest_class == pbase_class)
+    {
+        return C_TRUE;
+    }
+
+    /* Recursively check if test class has a matching base class */
+    if (((pPmClass_t)ptest_class)->cl_bases != C_NULL)
+    {
+        for (i = 0; i < ((pPmClass_t)ptest_class)->cl_bases->length; i++)
+        {
+            retval = class_isSubclass(((pPmClass_t)ptest_class)->cl_bases->val[i],
+                                        pbase_class);
+            if (retval)
+            {
+                break;
+            }
+        }
+    }
+    return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/class.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,132 @@
+/*
+# This file is Copyright 2009 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __CLASS_H__
+#define __CLASS_H__
+
+/** 
+ * \file
+ *  \brief Class header. 
+ */
+
+
+/**
+ * Class struct
+ *
+ * This C struct is used for PyMite class objects
+ * Note: Exceptions are objects.
+ */
+typedef struct PmClass_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Attributes dict */
+    pPmDict_t cl_attrs;
+    
+    /** Bases tuple */
+    pPmTuple_t cl_bases;
+} PmClass_t,
+ *pPmClass_t;
+
+/** Class instance struct */
+typedef struct PmInstance_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Class of this instance */
+    pPmClass_t cli_class;
+
+    /** Attributes dict */
+    pPmDict_t cli_attrs;
+} PmInstance_t, 
+*pPmInstance_t;
+
+/** Method struct */
+typedef struct PmMethod_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Class instance of this method */
+    pPmInstance_t m_instance;
+    
+    /** Func of this method */
+    pPmFunc_t m_func;
+    
+    /** Attributes dict */
+    pPmDict_t m_attrs;
+} PmMethod_t, 
+*pPmMethod_t;
+
+
+/**
+ * Creates a new Class object from the methods dict, bases tuple,
+ * and name string.
+ *
+ * @param   pmeths ptr to methods dict.
+ * @param   pbases ptr to bases tuple.
+ * @param   pname ptr to name string.
+ * @param   r_pclass Return by ref, ptr to new class
+ * @return  Return status
+ */
+PmReturn_t class_new(pPmObj_t pmeths, pPmObj_t pbases, pPmObj_t pname,
+                     pPmObj_t *r_pclass);
+
+/**
+ * Returns an instance of the given class
+ *
+ * @param pclass Pointer to class object
+ * @param r_pobj Return by ref, instance object
+ * @return  Return status
+ */
+PmReturn_t class_instantiate(pPmObj_t pclass, pPmObj_t *r_pobj);
+
+#ifdef HAVE_AUTOBOX
+/**
+ * Autoboxes an object in place
+ *
+ * @param pclass Pointer to object
+ * @return  Return status
+ */
+PmReturn_t class_autobox(pPmObj_t *pobj);
+#endif
+
+/**
+ * Returns a method based on the given inputs
+ *
+ * @param   pinstance ptr to instance
+ * @param   pfunc ptr to func
+ * @param   r_pmeth Return by ref, ptr to new method
+ * @return  Return status
+ */
+PmReturn_t class_method(pPmObj_t pinstance, pPmObj_t pfunc, pPmObj_t *r_pmeth);
+
+/**
+ * Returns the first attribute named __init__ in the class' inheritance tree
+ *
+ * @param   pobj ptr to class or instance to search
+ * @param   pname ptr to name of attr to find
+ * @param   r_pobj Return by ref, ptr to attr if found, or undetermined
+ * @return  Return status
+ */
+PmReturn_t class_getAttr(pPmObj_t pobj, pPmObj_t pname, pPmObj_t *r_pobj);
+
+/**
+ * Returns a C boolean if the base class is found in the inheritance tree
+ * of the test class.  NOTE: This function is recursive.
+ *
+ * @param   ptest_class ptr to class whose inheritance tree is searched
+ * @param   pbase_class ptr to class to look for
+ * @return  Returns C_TRUE if pbase_class is found in the inheritance tree;
+ *          C_FALSE otherwise.
+ */
+uint8_t class_isSubclass(pPmObj_t ptest_class, pPmObj_t pbase_class);
+
+#endif /* __CLASS_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/codeobj.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,176 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x01
+
+
+/**
+ * \file
+ * \brief CodeObj Type
+ *
+ * CodeObj type operations.
+ */
+
+
+#include "pm.h"
+
+
+/* The image format is defined by co_to_str() in src/tools/pmImgCreator.py */
+PmReturn_t
+co_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pco)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmObj_t pobj;
+    pPmCo_t pco = C_NULL;
+    uint8_t *pchunk;
+    uint8_t objid;
+#ifdef HAVE_DEBUG_INFO
+    uint8_t objtype;
+    uint16_t len_str;
+#endif /* HAVE_DEBUG_INFO */
+
+    /* Store ptr to top of code img (less type byte) */
+    uint8_t const *pci = *paddr - 1;
+
+    /* Get size of code img */
+    uint16_t size = mem_getWord(memspace, paddr);
+
+    /* Allocate a code obj */
+    retval = heap_getChunk(sizeof(PmCo_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pco = (pPmCo_t)pchunk;
+
+    /* Fill in the CO struct */
+    OBJ_SET_TYPE(pco, OBJ_TYPE_COB);
+    pco->co_memspace = memspace;
+    pco->co_argcount = mem_getByte(memspace, paddr);
+    pco->co_flags = mem_getByte(memspace, paddr);
+    pco->co_stacksize = mem_getByte(memspace, paddr);
+    pco->co_nlocals = mem_getByte(memspace, paddr);
+
+    /* Do not set code image address if image is in RAM.
+     * CIs in RAM have their image address set in obj_loadFromImgObj() */
+    pco->co_codeimgaddr = (memspace == MEMSPACE_RAM) ? C_NULL : pci;
+
+    /* Set these to null in case a GC occurs before their objects are alloc'd */
+    pco->co_names = C_NULL;
+    pco->co_consts = C_NULL;
+    pco->co_codeaddr = C_NULL;
+
+#ifdef HAVE_CLOSURES
+    pco->co_nfreevars = mem_getByte(memspace, paddr);
+    pco->co_cellvars = C_NULL;
+#endif /* HAVE_CLOSURES */
+
+#ifdef HAVE_DEBUG_INFO
+    pco->co_firstlineno = mem_getWord(memspace, paddr);
+    pco->co_lnotab = C_NULL;
+    pco->co_filename = C_NULL;
+#endif /* HAVE_DEBUG_INFO */
+
+    /* Load names (tuple obj) */
+    heap_gcPushTempRoot((pPmObj_t)pco, &objid);
+    retval = obj_loadFromImg(memspace, paddr, &pobj);
+    heap_gcPopTempRoot(objid);
+    PM_RETURN_IF_ERROR(retval);
+    pco->co_names = (pPmTuple_t)pobj;
+
+#ifdef HAVE_DEBUG_INFO
+    /* Get address in memspace of line number table (including length) */
+    objtype = mem_getByte(memspace, paddr);
+    C_ASSERT(objtype == OBJ_TYPE_STR);
+    pco->co_lnotab = *paddr;
+    len_str = mem_getWord(memspace, paddr);
+    *paddr = *paddr + len_str;
+
+    /* Get address in memspace of CO's filename (excluding length) */
+    objtype = mem_getByte(memspace, paddr);
+    C_ASSERT(objtype == OBJ_TYPE_STR);
+    len_str = mem_getWord(memspace, paddr);
+    pco->co_filename = *paddr;
+    *paddr = *paddr + len_str;
+#endif /* HAVE_DEBUG_INFO */
+
+    /* Load consts (tuple obj) assume it follows names */
+    heap_gcPushTempRoot((pPmObj_t)pco, &objid);
+    retval = obj_loadFromImg(memspace, paddr, &pobj);
+    heap_gcPopTempRoot(objid);
+    PM_RETURN_IF_ERROR(retval);
+    pco->co_consts = (pPmTuple_t)pobj;
+
+#ifdef HAVE_CLOSURES
+    heap_gcPushTempRoot((pPmObj_t)pco, &objid);
+    retval = obj_loadFromImg(memspace, paddr, &pobj);
+    heap_gcPopTempRoot(objid);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Save RAM, don't keep empty tuple */
+    if (((pPmTuple_t)pobj)->length == 0)
+    {
+        heap_freeChunk(pobj);
+    }
+    else
+    {
+        pco->co_cellvars = (pPmTuple_t)pobj;
+    }
+#endif /* HAVE_CLOSURES */
+
+    /* Start of bcode always follows consts */
+    pco->co_codeaddr = *paddr;
+
+    /* Set addr to point one past end of img */
+    *paddr = pci + size;
+
+    *r_pco = (pPmObj_t)pco;
+    return PM_RET_OK;
+}
+
+
+void
+co_rSetCodeImgAddr(pPmCo_t pco, uint8_t const *pimg)
+{
+    uint8_t i;
+
+    pco->co_codeimgaddr = pimg;
+
+    /* Set the image address for any COs in the constant pool */
+    for (i = 0; i < pco->co_consts->length; i++)
+    {
+        if (OBJ_GET_TYPE(pco->co_consts->val[i]) == OBJ_TYPE_COB)
+        {
+            co_rSetCodeImgAddr((pPmCo_t)pco->co_consts->val[i], pimg);
+        }
+    }
+
+    return;
+}
+
+
+PmReturn_t
+no_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pno)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmNo_t pno = C_NULL;
+    uint8_t *pchunk;
+
+    /* Allocate a code obj */
+    retval = heap_getChunk(sizeof(PmNo_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pno = (pPmNo_t)pchunk;
+
+    /* Fill in the NO struct */
+    OBJ_SET_TYPE(pno, OBJ_TYPE_NOB);
+    pno->no_argcount = mem_getByte(memspace, paddr);
+
+    /* Get index into native fxn table */
+    pno->no_funcindx = (int16_t)mem_getWord(memspace, paddr);
+
+    *r_pno = (pPmObj_t)pno;
+    return PM_RET_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/codeobj.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,211 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __CODEOBJ_H__
+#define __CODEOBJ_H__
+
+
+/**
+ * \file
+ * \brief CodeObj Type
+ *
+ * CodeObj type header.
+ */
+
+
+/** Code image field offset consts */
+#define CI_TYPE_FIELD       0
+#define CI_SIZE_FIELD       1
+#define CI_ARGCOUNT_FIELD   3
+#define CI_FLAGS_FIELD      4
+#define CI_STACKSIZE_FIELD  5
+#define CI_NLOCALS_FIELD    6
+
+#ifdef HAVE_CLOSURES
+# define CI_FREEVARS_FIELD  7
+# ifdef HAVE_DEBUG_INFO
+#  define CI_FIRST_LINE_NO  8
+#  define CI_NAMES_FIELD    10
+# else
+#  define CI_NAMES_FIELD    8
+# endif /* HAVE_DEBUG_INFO */
+#else
+# ifdef HAVE_DEBUG_INFO
+#  define CI_FIRST_LINE_NO  7
+#  define CI_NAMES_FIELD    9
+# else
+#  define CI_NAMES_FIELD    7
+# endif /* HAVE_DEBUG_INFO */
+#endif /* HAVE_CLOSURES */
+
+
+/** Native code image size */
+#define NATIVE_IMAGE_SIZE   4
+
+/* Masks for co_flags (from Python's code.h) */
+#define CO_OPTIMIZED 0x01
+#define CO_NEWLOCALS 0x02
+#define CO_VARARGS 0x04
+#define CO_VARKEYWORDS 0x08
+#define CO_NESTED 0x10
+#define CO_GENERATOR 0x20
+#define CO_NOFREE 0x40
+
+/**
+ * Code Object
+ *
+ * An extended object that holds only the most frequently used parts
+ * of the static code image.  Other parts can be obtained by
+ * inspecting the code image itself.
+ */
+typedef struct PmCo_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+    /** Address in progmem of the code image, or of code img obj in heap */
+    uint8_t const *co_codeimgaddr;
+    /** Address in RAM of names tuple */
+    pPmTuple_t co_names;
+    /** Address in RAM of constants tuple */
+    pPmTuple_t co_consts;
+    /** Address in memspace of bytecode (or native function) */
+    uint8_t const *co_codeaddr;
+
+#ifdef HAVE_DEBUG_INFO
+    /** Address in memspace of the line number table */
+    uint8_t const *co_lnotab;
+    /** Address in memspace of the filename */
+    uint8_t const *co_filename;
+    /** Line number of first source line of lnotab */
+    uint16_t co_firstlineno;
+#endif /* HAVE_DEBUG_INFO */
+
+#ifdef HAVE_CLOSURES
+    /** Address in RAM of cellvars tuple */
+    pPmTuple_t co_cellvars;
+    /** Number of freevars */
+    uint8_t co_nfreevars;
+#endif /* HAVE_CLOSURES */
+
+    /** Memory space selector */
+    PmMemSpace_t co_memspace:8;
+    /** Number of positional arguments the function expects */
+    uint8_t co_argcount;
+    /** Compiler flags */
+    uint8_t co_flags;
+    /** Stack size */
+    uint8_t co_stacksize;
+    /** Number of local variables */
+    uint8_t co_nlocals;
+} PmCo_t,
+ *pPmCo_t;
+
+/**
+ * Native Code Object
+ *
+ * An extended object that holds only the most frequently used parts
+ * of the static native image.  Other parts can be obtained by
+ * inspecting the native image itself.
+ */
+typedef struct PmNo_s
+{
+    /** object descriptor */
+    PmObjDesc_t od;
+    /** expected num args to the func */
+    int8_t no_argcount;
+    /** index into native function table */
+    int16_t no_funcindx;
+} PmNo_t,
+ *pPmNo_t;
+
+
+/**
+ * Creates a CodeObj by loading info from a code image in memory.
+ *
+ * An image is a static representation of a Python object.
+ * The process of converting an object to and from an image
+ * is also called marshalling.
+ * In PyMite, code images are the equivalent of .pyc files.
+ * Code images can only contain a select subset of object types
+ * (None, Int, Float, String, Slice?, Tuple, and CodeImg).
+ * All other types (Lists, Dicts, CodeObjs, Modules, Classes,
+ * Functions, ClassInstances) are built at runtime.
+ *
+ * All multibyte values are in Little Endian order
+ * (least significant byte comes first in the byte stream).
+ *
+ * memspace and *paddr determine the start of the code image.
+ * Load the code object with values from the code image,
+ * including the names and consts tuples.
+ * Leave contents of paddr pointing one byte past end of
+ * code img.
+ *
+ * The code image has the following structure:
+ *      -type:      8b - OBJ_TYPE_CIM
+ *      -size:      16b - number of bytes
+ *                  the code image occupies.
+ *      -argcount:  8b - number of arguments to this code obj.
+ *      -stacksz:   8b - the maximum arg-stack size needed.
+ *      -nlocals:   8b - number of local vars in the code obj.
+ *      -names:     Tuple - tuple of string objs.
+ *      -consts:    Tuple - tuple of objs.
+ *      -code:      8b[] - bytecode array.
+ *
+ * @param   memspace memory space containing image
+ * @param   paddr ptr to ptr to code img in memspace
+ *          return by reference: paddr points one byte
+ *          past end of code img
+ * @param   r_pco Return arg.  New code object with fields
+ *          filled in.
+ * @return  Return status
+ */
+PmReturn_t
+co_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pco);
+
+/**
+ * Recursively sets image address of the CO and all its nested COs
+ * in its constant pool.  This is done so that an image that was
+ * received during an interactive session will persist as long as any
+ * of its COs/funcs/objects is still alive.
+ *
+ * @param   pco Pointer to root code object whose images are set
+ * @param   pimg Pointer to very top of code image (PmodeImgObj)
+ */
+void co_rSetCodeImgAddr(pPmCo_t pco, uint8_t const *pimg);
+
+/**
+ * Creates a Native code object by loading a native image.
+ *
+ * An image is a static representation of a Python object.
+ * A native image is much smaller than a regular image
+ * because only two items of data are needed after the type:
+ * the number of args the func expects and the index into
+ * the native function table.
+ * A reference to the image is not needed since it is
+ * just as efficient to store the info in RAM as it is to
+ * store a pointer and memspace value.
+ *
+ * memspace and *paddr determine the start of the native image.
+ * Loads the argcount and the func index from the native object.
+ * Leaves contents of paddr pointing one byte past end of
+ * code img.
+ *
+ * The native image has the following structure:
+ *      -type:      8b - OBJ_TYPE_CIM
+ *      -argcount:  8b - number of arguments to this code obj.
+ *      -code:      16b - index into native function table.
+ *
+ * @param   memspace memory space containing image
+ * @param   paddr ptr to ptr to code img in memspace (return)
+ * @param   r_pno Return by reference, new code object
+ * @return  Return status
+ */
+PmReturn_t no_loadFromImg(PmMemSpace_t memspace,
+                          uint8_t const **paddr, pPmObj_t *r_pno);
+
+#endif /* __CODEOBJ_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/dict.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,375 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x02
+
+
+/**
+ * \file
+ * \brief Dict Object Type
+ *
+ * Dict object type operations.
+ */
+
+
+#include "pm.h"
+
+
+PmReturn_t
+dict_new(pPmObj_t *r_pdict)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmDict_t pdict = C_NULL;
+    uint8_t *pchunk;
+
+    /* Allocate a dict */
+    retval = heap_getChunk(sizeof(PmDict_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Init dict fields */
+    pdict = (pPmDict_t)pchunk;
+    OBJ_SET_TYPE(pdict, OBJ_TYPE_DIC);
+    pdict->length = 0;
+    pdict->d_keys = C_NULL;
+    pdict->d_vals = C_NULL;
+
+    *r_pdict = (pPmObj_t)pchunk;
+    return retval;
+}
+
+
+PmReturn_t
+dict_clear(pPmObj_t pdict)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(pdict != C_NULL);
+
+    /* Raise TypeError if arg is not a dict */
+    if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* clear length */
+    ((pPmDict_t)pdict)->length = 0;
+
+    /* Free the keys and values seglists if needed */
+    if (((pPmDict_t)pdict)->d_keys != C_NULL)
+    {
+        PM_RETURN_IF_ERROR(seglist_clear(((pPmDict_t)pdict)->d_keys));
+        PM_RETURN_IF_ERROR(heap_freeChunk((pPmObj_t)
+                                          ((pPmDict_t)pdict)->d_keys));
+        ((pPmDict_t)pdict)->d_keys = C_NULL;
+    }
+    if (((pPmDict_t)pdict)->d_vals != C_NULL)
+    {
+        PM_RETURN_IF_ERROR(seglist_clear(((pPmDict_t)pdict)->d_vals));
+        retval = heap_freeChunk((pPmObj_t)((pPmDict_t)pdict)->d_vals);
+        ((pPmDict_t)pdict)->d_vals = C_NULL;
+    }
+    return retval;
+}
+
+
+/*
+ * Sets a value in the dict using the given key.
+ *
+ * Scans dict for the key.  If key val found, replace old
+ * with new val.  If no key found, add key/val pair to dict.
+ */
+PmReturn_t
+dict_setItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t pval)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t indx;
+
+    C_ASSERT(pdict != C_NULL);
+    C_ASSERT(pkey != C_NULL);
+    C_ASSERT(pval != C_NULL);
+
+    /* If it's not a dict, raise TypeError */
+    if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* #112: Force Dict keys to be of hashable type */
+    /* If key is not hashable, raise TypeError */
+    if (OBJ_GET_TYPE(pkey) > OBJ_TYPE_HASHABLE_MAX)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* #147: Change boolean keys to integers */
+    if (pkey == PM_TRUE)
+    {
+        pkey = PM_ONE;
+    }
+    else if (pkey == PM_FALSE)
+    {
+        pkey = PM_ZERO;
+    }
+
+    /*
+     * #115: If this is the first key/value pair to be added to the Dict,
+     * allocate the key and value seglists that hold those items
+     */
+    if (((pPmDict_t)pdict)->length == 0)
+    {
+        retval = seglist_new(&((pPmDict_t)pdict)->d_keys);
+        PM_RETURN_IF_ERROR(retval);
+        retval = seglist_new(&((pPmDict_t)pdict)->d_vals);
+        PM_RETURN_IF_ERROR(retval);
+    }
+    else
+    {
+        /* Check for matching key */
+        indx = 0;
+        retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx);
+
+        /* If found a matching key, replace val obj */
+        if (retval == PM_RET_OK)
+        {
+            retval = seglist_setItem(((pPmDict_t)pdict)->d_vals, pval, indx);
+            return retval;
+        }
+    }
+
+    /* Otherwise, insert the key,val pair */
+    retval = seglist_insertItem(((pPmDict_t)pdict)->d_keys, pkey, 0);
+    PM_RETURN_IF_ERROR(retval);
+    retval = seglist_insertItem(((pPmDict_t)pdict)->d_vals, pval, 0);
+    ((pPmDict_t)pdict)->length++;
+
+    return retval;
+}
+
+
+PmReturn_t
+dict_getItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t indx = 0;
+
+/*    C_ASSERT(pdict != C_NULL);*/
+
+    /* if it's not a dict, raise TypeError */
+    if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* if dict is empty, raise KeyError */
+    if (((pPmDict_t)pdict)->length <= 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_KEY);
+        return retval;
+    }
+
+    /* #147: Change boolean keys to integers */
+    if (pkey == PM_TRUE)
+    {
+        pkey = PM_ONE;
+    }
+    else if (pkey == PM_FALSE)
+    {
+        pkey = PM_ZERO;
+    }
+
+    /* check for matching key */
+    retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx);
+    /* if key not found, raise KeyError */
+    if (retval == PM_RET_NO)
+    {
+        PM_RAISE(retval, PM_RET_EX_KEY);
+    }
+    /* return any other error */
+    PM_RETURN_IF_ERROR(retval);
+
+    /* key was found, get obj from vals */
+    retval = seglist_getItem(((pPmDict_t)pdict)->d_vals, indx, r_pobj);
+    return retval;
+}
+
+
+#ifdef HAVE_DEL
+PmReturn_t
+dict_delItem(pPmObj_t pdict, pPmObj_t pkey)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t indx = 0;
+
+    C_ASSERT(pdict != C_NULL);
+
+    /* Check for matching key */
+    retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx);
+
+    /* Raise KeyError if key is not found */
+    if (retval == PM_RET_NO)
+    {
+        PM_RAISE(retval, PM_RET_EX_KEY);
+    }
+
+    /* Return any other error */
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Remove the key and value */
+    retval = seglist_removeItem(((pPmDict_t)pdict)->d_keys, indx);
+    PM_RETURN_IF_ERROR(retval);
+    retval = seglist_removeItem(((pPmDict_t)pdict)->d_vals, indx);
+
+    /* Reduce the item count */
+    ((pPmDict_t)pdict)->length--;
+
+    return retval;
+}
+#endif /* HAVE_DEL */
+
+
+#ifdef HAVE_PRINT
+PmReturn_t
+dict_print(pPmObj_t pdict)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t index;
+    pSeglist_t keys,
+      vals;
+    pPmObj_t pobj1;
+
+    C_ASSERT(pdict != C_NULL);
+
+    /* if it's not a dict, raise TypeError */
+    if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    plat_putByte('{');
+
+    keys = ((pPmDict_t)pdict)->d_keys;
+    vals = ((pPmDict_t)pdict)->d_vals;
+
+    /* if dict is empty, raise KeyError */
+    for (index = 0; index < ((pPmDict_t)pdict)->length; index++)
+    {
+        if (index != 0)
+        {
+            plat_putByte(',');
+            plat_putByte(' ');
+        }
+        retval = seglist_getItem(keys, index, &pobj1);
+        PM_RETURN_IF_ERROR(retval);
+        retval = obj_print(pobj1, C_FALSE, C_TRUE);
+        PM_RETURN_IF_ERROR(retval);
+
+        plat_putByte(':');
+        retval = seglist_getItem(vals, index, &pobj1);
+        PM_RETURN_IF_ERROR(retval);
+        retval = obj_print(pobj1, C_FALSE, C_TRUE);
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    return plat_putByte('}');
+}
+#endif /* HAVE_PRINT */
+
+
+PmReturn_t
+dict_update(pPmObj_t pdestdict, pPmObj_t psourcedict, uint8_t omit_underscored)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t i;
+    pPmObj_t pkey;
+    pPmObj_t pval;
+
+    C_ASSERT(pdestdict != C_NULL);
+    C_ASSERT(psourcedict != C_NULL);
+
+    /* If it's not a dict, raise TypeError */
+    if (OBJ_GET_TYPE(pdestdict) != OBJ_TYPE_DIC)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* If it's not a dict, raise TypeError */
+    if (OBJ_GET_TYPE(psourcedict) != OBJ_TYPE_DIC)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Iterate over the add-on dict */
+    for (i = 0; i < ((pPmDict_t)psourcedict)->length; i++)
+    {
+        /* Get the key,val from the add-on dict */
+        retval = seglist_getItem(((pPmDict_t)psourcedict)->d_keys, i, &pkey);
+        PM_RETURN_IF_ERROR(retval);
+        retval = seglist_getItem(((pPmDict_t)psourcedict)->d_vals, i, &pval);
+        PM_RETURN_IF_ERROR(retval);
+
+        if (!(omit_underscored && (OBJ_GET_TYPE(pkey) == OBJ_TYPE_STR)
+              && ((pPmString_t)pkey)->val[0] == '_'))
+        {
+            /* Set the key,val to the destination dict */
+            retval = dict_setItem(pdestdict, pkey, pval);
+            PM_RETURN_IF_ERROR(retval);
+        }
+    }
+
+    return retval;
+}
+
+
+int8_t
+dict_compare(pPmObj_t d1, pPmObj_t d2)
+{
+    pPmDict_t pd1 = (pPmDict_t)d1;
+    pPmDict_t pd2 = (pPmDict_t)d2;
+    pPmObj_t pkey1;
+    pPmObj_t pval1;
+    pPmObj_t pval2;
+    uint16_t i;
+    PmReturn_t retval;
+
+    /* Return if lengths are not equal */
+    if (pd1->length != pd2->length)
+    {
+        return C_DIFFER;
+    }
+
+    for (i = 0; i < pd1->length; i++)
+    {
+        /* Get the key,val from one dict */
+        retval = seglist_getItem(pd1->d_keys, i, &pkey1);
+        PM_RETURN_IF_ERROR(retval);
+        retval = seglist_getItem(pd1->d_vals, i, &pval1);
+        PM_RETURN_IF_ERROR(retval);
+
+        /* Return if the key,val pair is not in the other dict */
+        retval = dict_getItem(d2, pkey1, &pval2);
+        if (retval != PM_RET_OK)
+        {
+            return C_DIFFER;
+        }
+        if (obj_compare(pval1, pval2) != C_SAME)
+        {
+            return C_DIFFER;
+        }
+    }
+
+    /* All key,values match */
+    return C_SAME;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/dict.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,130 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __DICT_H__
+#define __DICT_H__
+
+
+/**
+ * \file
+ * \brief Dict Object Type
+ *
+ * Dict object type header.
+ */
+
+
+/**
+ * Dict
+ *
+ * Contains ptr to two seglists,
+ * one for keys, the other for values;
+ * and a length, the number of key/value pairs.
+ */
+typedef struct PmDict_s
+{
+    /** object descriptor */
+    PmObjDesc_t od;
+    /** number of key,value pairs in the dict */
+    uint16_t length;
+    /** ptr to seglist containing keys */
+    pSeglist_t d_keys;
+    /** ptr to seglist containing values */
+    pSeglist_t d_vals;
+} PmDict_t,
+ *pPmDict_t;
+
+
+/**
+ * Clears the contents of a dict.
+ * after this operation, the dict should in the same state
+ * as if it were just created using dict_new().
+ *
+ * @param   pdict ptr to dict to clear.
+ * @return  nothing
+ */
+PmReturn_t dict_clear(pPmObj_t pdict);
+
+/**
+ * Gets the value in the dict using the given key.
+ *
+ * @param   pdict ptr to dict to search
+ * @param   pkey ptr to key obj
+ * @param   r_pobj Return; addr of ptr to obj
+ * @return  Return status
+ */
+PmReturn_t dict_getItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t *r_pobj);
+
+#ifdef HAVE_DEL
+/**
+ * Removes a key and value from the dict.
+ * Throws TypeError if pdict is not a dict.
+ * Throws KeyError if pkey does not exist in pdict.
+ *
+ * @param   pdict Ptr to dict to search
+ * @param   pkey Ptr to key obj
+ * @return  Return status
+ */
+PmReturn_t dict_delItem(pPmObj_t pdict, pPmObj_t pkey);
+#endif /* HAVE_DEL */
+
+/**
+ * Allocates space for a new Dict.
+ * Return a pointer to the dict by reference.
+ *
+ * @param   r_pdict Return; Addr of ptr to dict
+ * @return  Return status
+ */
+PmReturn_t dict_new(pPmObj_t *r_pdict);
+
+/**
+ * Sets a value in the dict using the given key.
+ *
+ * If the dict already contains a matching key, the value is
+ * replaced; otherwise the new key,val pair is inserted
+ * at the front of the dict (for fast lookup).
+ * In the later case, the length of the dict is incremented.
+ *
+ * @param   pdict ptr to dict in which (key,val) will go
+ * @param   pkey ptr to key obj
+ * @param   pval ptr to val obj
+ * @return  Return status
+ */
+PmReturn_t dict_setItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t pval);
+
+#ifdef HAVE_PRINT
+/**
+ * Prints out a dict. Uses obj_print() to print elements.
+ *
+ * @param pobj Object to print.
+ * @return Return status
+ */
+PmReturn_t dict_print(pPmObj_t pdict);
+#endif /* HAVE_PRINT */
+
+/**
+ * Updates the destination dict with the key,value pairs from the source dict
+ *
+ * @param   pdestdict ptr to destination dict in which key,val pairs will go
+ * @param   psourcedict ptr to source dict which has all key,val pairs to copy
+ * @param   omit_underscored Boolean set to true to omit key,val pairs where
+ *          the key starts with an underscore '_'.
+ * @return  Return status
+ */
+PmReturn_t dict_update(pPmObj_t pdestdict, pPmObj_t psourcedict,
+                       uint8_t omit_underscored);
+
+/**
+ * Returns C_SAME if the two given dictionaries have the same contents
+ *
+ * @param d1 ptr to a dictionary object
+ * @param d2 ptr to another dictionary object
+ * @return C_DIFFER or C_SAME
+ */
+int8_t dict_compare(pPmObj_t d1, pPmObj_t d2);
+
+#endif /* __DICT_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/float.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,217 @@
+/*
+# This file is Copyright 2009 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x17
+
+
+/**
+ * \file
+ * \brief Float Object Type
+ *
+ * Float object type operations.
+ */
+
+
+#include "pm.h"
+
+
+#ifdef HAVE_FLOAT
+#include <math.h>
+
+
+PmReturn_t
+float_new(float f, pPmObj_t *r_pf)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    retval = heap_getChunk(sizeof(PmFloat_t), (uint8_t **)r_pf);
+    PM_RETURN_IF_ERROR(retval);
+    OBJ_SET_TYPE(*r_pf, OBJ_TYPE_FLT);
+    ((pPmFloat_t) * r_pf)->val = f;
+    return retval;
+}
+
+
+#ifdef HAVE_PRINT
+
+PmReturn_t
+float_print(pPmObj_t pf)
+{
+    uint8_t tBuffer[32];
+    uint8_t bytesWritten;
+    uint8_t *p;
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(pf != C_NULL);
+
+    /* Raise TypeError if obj is not an float */
+    if (OBJ_GET_TYPE(pf) != OBJ_TYPE_FLT)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* #212: Use homebrew float formatter */
+    retval = sli_ftoa(((pPmFloat_t)pf)->val, tBuffer, sizeof(tBuffer));
+    bytesWritten = sli_strlen((char *)tBuffer);
+
+    /* Remove trailing zeroes (per Python convention) */
+    for (p = &tBuffer[bytesWritten] - 1; 
+         p[0] == '0' && p[-1] != '.'; 
+         --p, bytesWritten--);
+    ++p;
+    *p = '\0';
+
+    /* Sanity check */
+    C_ASSERT(bytesWritten != 0);
+    C_ASSERT(bytesWritten < sizeof(tBuffer));
+
+    sli_puts(tBuffer);
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+float_negative(pPmObj_t pf, pPmObj_t *r_pf)
+{
+    /* Create new int obj */
+    return float_new(-((pPmFloat_t) pf)->val, r_pf);
+}
+
+#endif /* HAVE_PRINT */
+
+
+PmReturn_t
+float_op(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pn, int8_t op)
+{
+    float x;
+    float y;
+    float r;
+    PmReturn_t retval;
+
+    /* Raise TypeError if args aren't ints or floats */
+    if (((OBJ_GET_TYPE(px) != OBJ_TYPE_INT)
+         && (OBJ_GET_TYPE(px) != OBJ_TYPE_FLT))
+        || ((OBJ_GET_TYPE(py) != OBJ_TYPE_INT)
+            && (OBJ_GET_TYPE(py) != OBJ_TYPE_FLT)))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get the values as floats */
+    if (OBJ_GET_TYPE(px) == OBJ_TYPE_INT)
+    {
+        x = (float)((pPmInt_t)px)->val;
+    }
+    else
+    {
+        x = ((pPmFloat_t) px)->val;
+    }
+
+    if (OBJ_GET_TYPE(py) == OBJ_TYPE_INT)
+    {
+        y = (float)((pPmInt_t)py)->val;
+    }
+    else
+    {
+        y = ((pPmFloat_t) py)->val;
+    }
+
+    /* Raise ZeroDivisionError if denominator is zero */
+    if ((y == 0.0) && ((op == '/') || (op == '%')))
+    {
+        PM_RAISE(retval, PM_RET_EX_ZDIV);
+        return retval;
+    }
+
+    /* Calculate x raised to y */
+    switch (op)
+    {
+        /* *INDENT-OFF* */
+        case '+': r = x + y; break;
+        case '-': r = x - y; break;
+        case '*': r = x * y; break;
+        case '/': r = x / y; break;
+        case '%': r = fmodf(x, y); break;
+        case 'P': r = powf(x, y); break;
+        default: r = 0.0; break;
+        /* *INDENT-ON* */
+    }
+
+    retval = float_new(r, r_pn);
+
+    return retval;
+}
+
+PmReturn_t
+float_compare(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pobj, PmCompare_t cmp)
+{
+    float x;
+    float y;
+    PmReturn_t retval = PM_RET_OK;
+    int8_t t8 = 0;
+
+    /* Raise TypeError if args aren't ints or floats */
+    if (((OBJ_GET_TYPE(px) != OBJ_TYPE_INT)
+         && (OBJ_GET_TYPE(px) != OBJ_TYPE_FLT))
+        || ((OBJ_GET_TYPE(py) != OBJ_TYPE_INT)
+            && (OBJ_GET_TYPE(py) != OBJ_TYPE_FLT)))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Get the values as floats */
+    if (OBJ_GET_TYPE(px) == OBJ_TYPE_INT)
+    {
+        x = (float)((pPmInt_t)px)->val;
+    }
+    else
+    {
+        x = ((pPmFloat_t) px)->val;
+    }
+
+    if (OBJ_GET_TYPE(py) == OBJ_TYPE_INT)
+    {
+        y = (float)((pPmInt_t)py)->val;
+    }
+    else
+    {
+        y = ((pPmFloat_t) py)->val;
+    }
+
+    switch (cmp)
+    {
+        /* *INDENT-OFF* */
+        case COMP_LT: t8 = (int8_t)(x <  y); break;
+        case COMP_LE: t8 = (int8_t)(x <= y); break;
+        case COMP_EQ: t8 = (int8_t)(x == y); break;
+        case COMP_NE: t8 = (int8_t)(x != y); break;
+        case COMP_GT: t8 = (int8_t)(x >  y); break;
+        case COMP_GE: t8 = (int8_t)(x >= y); break;
+        case COMP_IS: t8 = (int8_t)(px == py); break;
+        case COMP_IS_NOT: t8 = (int8_t)(px != py);break;
+        case COMP_IN:
+        case COMP_NOT_IN:
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            break;
+
+        default:
+            /* Other compares are not yet supported */
+            PM_RAISE(retval, PM_RET_EX_SYS);
+            break;
+        /* *INDENT-ON* */
+    }
+    *r_pobj = (t8) ? PM_TRUE : PM_FALSE;
+
+    return retval;
+}
+
+#endif /* HAVE_FLOAT */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/float.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,95 @@
+/*
+# This file is Copyright 2009 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __FLOAT_H__
+#define __FLOAT_H__
+
+
+/**
+ * \file
+ * \brief Float Object Type
+ *
+ * Float object type header.
+ */
+
+
+/**
+ * Float obj
+ *
+ * 32b floating point number
+ */
+typedef struct PmFloat_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Float value */
+    float val;
+} PmFloat_t, *pPmFloat_t;
+
+
+#ifdef HAVE_FLOAT
+
+/**
+ * Creates a new Float object
+ *
+ * @param   f Value to assign float (signed 32-bit).
+ * @param   r_pint Return by ref, ptr to new float
+ * @return  Return status
+ */
+PmReturn_t float_new(float f, pPmObj_t *r_pf);
+
+/**
+ * Implements the UNARY_NEGATIVE bcode.
+ *
+ * Creates a new float with a value that is the negative of the given float.
+ *
+ * @param   pobj Pointer to target object
+ * @param   r_pint Return by ref, ptr to float
+ * @return  Return status
+ */
+PmReturn_t float_negative(pPmObj_t pf, pPmObj_t *r_pf);
+
+/**
+ * Returns by reference a float that is x op y.
+ *
+ * @param px The float left-hand argument
+ * @param py The float right-hand argument
+ * @param r_pn The return value of x op y
+ * @param op The operator (+,-,*,/ and power)
+ * @return Return status
+ */
+PmReturn_t float_op(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pn, int8_t op);
+
+/**
+ * Returns by reference a boolean that is x op y.
+ *
+ * @param px The float left-hand argument
+ * @param py The float right-hand argument
+ * @param r_pn The return value of x cmp y
+ * @param cmp The comparison operator
+ * @return Return status
+ */
+PmReturn_t float_compare(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pobj,
+                         PmCompare_t cmp);
+
+#ifdef HAVE_PRINT
+/**
+ * Sends out a float object.
+ * The number is preceded with a "-" when necessary.
+ *
+ * @param pObj Ptr to float object
+ * @return Return status
+ */
+PmReturn_t float_print(pPmObj_t pf);
+
+#endif /* HAVE_PRINT */
+
+#endif /* HAVE_FLOAT */
+
+#endif /* __FLOAT_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/frame.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,100 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x03
+
+
+/**
+ * \file
+ * \brief VM Frame
+ *
+ * VM frame operations.
+ */
+
+
+#include "pm.h"
+
+
+PmReturn_t
+frame_new(pPmObj_t pfunc, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t fsize = 0;
+    pPmCo_t pco = C_NULL;
+    pPmFrame_t pframe = C_NULL;
+    uint8_t *pchunk;
+
+    /* Get fxn's code obj */
+    pco = ((pPmFunc_t)pfunc)->f_co;
+
+    /* TypeError if passed func's CO is not a true COB */
+    if (OBJ_GET_TYPE(pco) != OBJ_TYPE_COB)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+#ifdef HAVE_GENERATORS
+    /* #207: Initializing a Generator using CALL_FUNC needs extra stack slot */
+    fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals + 2) * sizeof(pPmObj_t);
+#elif defined(HAVE_CLASSES)
+    /* #230: Calling a class's __init__() takes two extra spaces on the stack */
+    fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals + 1) * sizeof(pPmObj_t);
+#else
+    fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals - 1) * sizeof(pPmObj_t);
+#endif /* HAVE_CLASSES */
+
+#ifdef HAVE_CLOSURES
+    /* #256: Add support for closures */
+    fsize = fsize + pco->co_nfreevars
+            + ((pco->co_cellvars == C_NULL) ? 0 : pco->co_cellvars->length);
+#endif /* HAVE_CLOSURES */
+
+    /* Allocate a frame */
+    retval = heap_getChunk(fsize, &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pframe = (pPmFrame_t)pchunk;
+
+    /* Set frame fields */
+    OBJ_SET_TYPE(pframe, OBJ_TYPE_FRM);
+    pframe->fo_back = C_NULL;
+    pframe->fo_func = (pPmFunc_t)pfunc;
+    pframe->fo_memspace = pco->co_memspace;
+
+    /* Init instruction pointer and block stack */
+    pframe->fo_ip = pco->co_codeaddr;
+    pframe->fo_blockstack = C_NULL;
+
+    /* Get globals and attrs from the function object */
+    pframe->fo_globals = ((pPmFunc_t)pfunc)->f_globals;
+    pframe->fo_attrs = ((pPmFunc_t)pfunc)->f_attrs;
+
+#ifndef HAVE_CLOSURES
+    /* Empty stack points to one past locals */
+    pframe->fo_sp = &(pframe->fo_locals[pco->co_nlocals]);
+#else
+    /* #256: Add support for closures */
+    pframe->fo_sp = &(pframe->fo_locals[pco->co_nlocals + pco->co_nfreevars
+        + ((pco->co_cellvars == C_NULL) ? 0 : pco->co_cellvars->length)]);
+#endif /* HAVE_CLOSURES */
+
+    /* By default, this is a normal frame, not an import or __init__ one */
+    pframe->fo_isImport = 0;
+#ifdef HAVE_CLASSES
+    pframe->fo_isInit = 0;
+#endif
+
+    /* Clear the stack */
+    sli_memset((unsigned char *)&(pframe->fo_locals), (char const)0,
+               (unsigned int)fsize - sizeof(PmFrame_t));
+
+    /* Return ptr to frame */
+    *r_pobj = (pPmObj_t)pframe;
+    return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/frame.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,175 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __FRAME_H__
+#define __FRAME_H__
+
+
+/**
+ * \file
+ * \brief VM Frame
+ *
+ * VM frame header.
+ */
+
+
+/**
+ * The maximum number of local variables a native function can have.
+ * This defines the length of the locals array in the native frame struct.
+ */
+#define NATIVE_MAX_NUM_LOCALS   8
+
+
+/**
+ * Block Type
+ *
+ * Numerical values to put in the 'b_type' field of the tPmBlockType struct.
+ */
+typedef enum PmBlockType_e
+{
+    /** Invalid block type */
+    B_INVALID = 0,
+
+    /** Loop type */
+    B_LOOP,
+
+    /** Try type */
+    B_TRY
+} PmBlockType_t, *pPmBlockType_t;
+
+
+/**
+ * Block
+ *
+ * Extra info for loops and trys (others?)
+ * Frames use linked list of blocks to handle
+ * nested loops and try-catch blocks.
+ */
+typedef struct PmBlock_s
+{
+    /** Obligatory obj descriptor */
+    PmObjDesc_t od;
+
+    /** Ptr to backup stack ptr */
+    pPmObj_t *b_sp;
+
+    /** Handler fxn obj */
+    uint8_t const *b_handler;
+
+    /** Block type */
+    PmBlockType_t b_type:8;
+
+    /** Next block in stack */
+    struct PmBlock_s *next;
+} PmBlock_t,
+ *pPmBlock_t;
+
+
+/**
+ * Frame
+ *
+ * A struct that holds the execution frame of a function, including the stack,
+ * local vars and pointer to the code object.
+ *
+ * This struct doesn't declare the stack.
+ * frame_new() is responsible for allocating the extra memory
+ * at the tail of fo_locals[] to hold both the locals and stack.
+ */
+typedef struct PmFrame_s
+{
+    /** Obligatory obj descriptor */
+    PmObjDesc_t od;
+
+    /** Ptr to previous frame obj */
+    struct PmFrame_s *fo_back;
+
+    /** Ptr to fxn obj */
+    pPmFunc_t fo_func;
+
+    /** Mem space where func's CO comes from */
+    PmMemSpace_t fo_memspace:8;
+
+    /** Instrxn ptr (pts into memspace) */
+    uint8_t const *fo_ip;
+
+    /** Linked list of blocks */
+    pPmBlock_t fo_blockstack;
+
+    /** Local attributes dict (non-fast locals) */
+    pPmDict_t fo_attrs;
+
+    /** Global attributes dict (pts to root frame's globals */
+    pPmDict_t fo_globals;
+
+    /** Points to next empty slot in fo_locals (1 past TOS) */
+    pPmObj_t *fo_sp;
+
+    /** Frame can be an import-frame that handles RETURN differently */
+    uint8_t fo_isImport:1;
+
+#ifdef HAVE_CLASSES
+    /** Flag to indicate class initailzer frame; handle RETURN differently */
+    uint8_t fo_isInit:1;
+#endif /* HAVE_CLASSES */
+
+    /** Array of local vars and stack (space appended at alloc) */
+    pPmObj_t fo_locals[1];
+    /* WARNING: Do not put new fields below fo_locals */
+} PmFrame_t,
+ *pPmFrame_t;
+
+
+/**
+ * Native Frame
+ *
+ * A struct that holds the execution frame of a native function,
+ * including the args and single stack slot, and pointer to the code object.
+ *
+ * This struct doesn't need an OD because it is only used statically in the
+ * globals struct.  There's only one native frame, the global one.
+ * This happens because a native function is a leaf node
+ * in the call tree (a native func can't call python funcs).
+ */
+typedef struct PmNativeFrame_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Ptr to previous frame obj */
+    struct PmFrame_s *nf_back;
+
+    /** Ptr to fxn obj */
+    pPmFunc_t nf_func;
+
+    /** Single stack slot */
+    pPmObj_t nf_stack;
+
+    /** Boolean to indicate if the native frame is active */
+    uint8_t nf_active;
+
+    /** Number of args passed to the native function */
+    uint8_t nf_numlocals;
+
+    /** Local vars */
+    pPmObj_t nf_locals[NATIVE_MAX_NUM_LOCALS];
+} PmNativeFrame_t,
+ *pPmNativeFrame_t;
+
+
+/**
+ * Allocate space for a new frame, fill its fields
+ * with respect to the given function object.
+ * Return pointer to the new frame.
+ *
+ * @param   pfunc ptr to Function object.
+ * @param   r_pobj Return value; the new frame.
+ * @return  Return status.
+ */
+PmReturn_t frame_new(pPmObj_t pfunc, pPmObj_t *r_pobj);
+
+#endif /* __FRAME_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/func.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,73 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x04
+
+
+/**
+ * \file
+ * \brief Function Object Type
+ *
+ * Function object type operations.
+ */
+
+
+#include "pm.h"
+
+
+PmReturn_t
+func_new(pPmObj_t pco, pPmObj_t pglobals, pPmObj_t *r_pfunc)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmFunc_t pfunc = C_NULL;
+    uint8_t *pchunk;
+    pPmObj_t pobj;
+    uint8_t objid;
+
+    C_ASSERT(OBJ_GET_TYPE(pco) != OBJ_TYPE_COB
+             || OBJ_GET_TYPE(pco) != OBJ_TYPE_NOB);
+    C_ASSERT(OBJ_GET_TYPE(pglobals) == OBJ_TYPE_DIC);
+
+    /* Allocate a func obj */
+    retval = heap_getChunk(sizeof(PmFunc_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pfunc = (pPmFunc_t)pchunk;
+
+    /* Init func */
+    OBJ_SET_TYPE(pfunc, OBJ_TYPE_FXN);
+    pfunc->f_co = (pPmCo_t)pco;
+    pfunc->f_globals = C_NULL;
+    pfunc->f_attrs = C_NULL;
+
+#ifdef HAVE_DEFAULTARGS
+    /* Clear default args (will be set later, if at all) */
+    pfunc->f_defaultargs = C_NULL;
+#endif /* HAVE_DEFAULTARGS */
+
+#ifdef HAVE_CLOSURES
+    /* Clear field for closure tuple */
+    pfunc->f_closure = C_NULL;
+#endif /* HAVE_CLOSURES */
+
+    /* Create attrs dict for regular func (not native) */
+    if (OBJ_GET_TYPE(pco) == OBJ_TYPE_COB)
+    {
+        heap_gcPushTempRoot((pPmObj_t)pfunc, &objid);
+        retval = dict_new(&pobj);
+        heap_gcPopTempRoot(objid);
+        PM_RETURN_IF_ERROR(retval);
+        pfunc->f_attrs = (pPmDict_t)pobj;
+
+        /* Store the given globals dict */
+        pfunc->f_globals = (pPmDict_t)pglobals;
+    }
+
+    *r_pfunc = (pPmObj_t)pfunc;
+    return PM_RET_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/func.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,67 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __FUNC_H__
+#define __FUNC_H__
+
+/**
+ * \file
+ * \brief Function Object Type
+ *
+ * Function object type header.
+ */
+
+/**
+ * Function obj
+ *
+ * A function is like an instance of a code obj.
+ * Contains ptr to its code obj and has its own attributes dict.
+ *
+ * The first (__main__) module that is executed has a function obj
+ * created for it to execute the bytecode which builds the module.
+ */
+typedef struct PmFunc_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Ptr to code obj */
+    pPmCo_t f_co;
+
+    /** Ptr to attribute dict */
+    pPmDict_t f_attrs;
+
+    /** Ptr to globals dict */
+    pPmDict_t f_globals;
+
+#ifdef HAVE_DEFAULTARGS
+    /** Ptr to tuple holding default args */
+    pPmTuple_t f_defaultargs;
+#endif /* HAVE_DEFAULTARGS */
+
+#ifdef HAVE_CLOSURES
+    /** Ptr to tuple of cell values */
+    pPmTuple_t f_closure;
+#endif /* HAVE_CLOSURES */
+
+} PmFunc_t,
+ *pPmFunc_t;
+
+
+/**
+ * Creates a Function Obj for the given Code Obj.
+ * Allocate space for a Func obj and fill the fields.
+ *
+ * @param   pco ptr to code obj
+ * @param   pglobals ptr to globals dict (from containing func/module)
+ * @param   r_pfunc Return by reference; pointer to new function
+ * @return  Return status
+ */
+PmReturn_t func_new(pPmObj_t pco, pPmObj_t pglobals, pPmObj_t *r_pfunc);
+
+#endif /* __FUNC_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/global.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,256 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x05
+
+
+/**
+ * \file
+ * \brief VM Globals
+ *
+ * VM globals operations.
+ * PyMite's global struct def and initial values.
+ */
+
+
+#include "pm.h"
+
+
+extern unsigned char const *stdlib_img;
+
+static uint8_t const *bistr = (uint8_t const *)"__bi";
+
+
+/** Most PyMite globals all in one convenient place */
+volatile PmVmGlobal_t gVmGlobal;
+
+
+PmReturn_t
+global_init(void)
+{
+    PmReturn_t retval;
+    uint8_t *codestr = (uint8_t *)"code";
+    uint8_t *pchunk;
+    pPmObj_t pobj;
+#ifdef HAVE_CLASSES
+    uint8_t const *initstr = (uint8_t const *)"__init__"; 
+#endif /* HAVE_CLASSES */
+#ifdef HAVE_GENERATORS
+    uint8_t const *genstr = (uint8_t const *)"Generator";
+    uint8_t const *nextstr = (uint8_t const *)"next";
+#endif /* HAVE_GENERATORS */
+#ifdef HAVE_ASSERT
+    uint8_t const *exnstr = (uint8_t const *)"Exception";
+#endif /* HAVE_ASSERT */
+#ifdef HAVE_BYTEARRAY
+    uint8_t const *pbastr = (uint8_t const *)"bytearray";
+#endif /* HAVE_BYTEARRAY */
+    uint8_t const *pmdstr = (uint8_t const *)"__md";
+
+    /* Clear the global struct */
+    sli_memset((uint8_t *)&gVmGlobal, '\0', sizeof(PmVmGlobal_t));
+
+    /* Set the PyMite release num (for debug and post mortem) */
+    gVmGlobal.errVmRelease = PM_RELEASE;
+
+    /* Init zero */
+    retval = heap_getChunk(sizeof(PmInt_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pobj = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(pobj, OBJ_TYPE_INT);
+    ((pPmInt_t)pobj)->val = (int32_t)0;
+    gVmGlobal.pzero = (pPmInt_t)pobj;
+
+    /* Init one */
+    retval = heap_getChunk(sizeof(PmInt_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pobj = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(pobj, OBJ_TYPE_INT);
+    ((pPmInt_t)pobj)->val = (int32_t)1;
+    gVmGlobal.pone = (pPmInt_t)pobj;
+
+    /* Init negone */
+    retval = heap_getChunk(sizeof(PmInt_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pobj = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(pobj, OBJ_TYPE_INT);
+    ((pPmInt_t)pobj)->val = (int32_t)-1;
+    gVmGlobal.pnegone = (pPmInt_t)pobj;
+
+    /* Init False */
+    retval = heap_getChunk(sizeof(PmBoolean_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pobj = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(pobj, OBJ_TYPE_BOOL);
+    ((pPmBoolean_t) pobj)->val = (int32_t)C_FALSE;
+    gVmGlobal.pfalse = (pPmInt_t)pobj;
+
+    /* Init True */
+    retval = heap_getChunk(sizeof(PmBoolean_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pobj = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(pobj, OBJ_TYPE_BOOL);
+    ((pPmBoolean_t) pobj)->val = (int32_t)C_TRUE;
+    gVmGlobal.ptrue = (pPmInt_t)pobj;
+
+    /* Init None */
+    retval = heap_getChunk(sizeof(PmObj_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pobj = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(pobj, OBJ_TYPE_NON);
+    gVmGlobal.pnone = pobj;
+
+    /* Init "code" string obj */
+    retval = string_new((uint8_t const **)&codestr, &pobj);
+    PM_RETURN_IF_ERROR(retval);
+    gVmGlobal.pcodeStr = (pPmString_t)pobj;
+
+#ifdef HAVE_CLASSES
+    /* Init "__init__" string obj */
+    retval = string_new((uint8_t const **)&initstr, &pobj);
+    PM_RETURN_IF_ERROR(retval);
+    gVmGlobal.pinitStr = (pPmString_t)pobj;
+#endif /* HAVE_CLASSES */
+
+#ifdef HAVE_GENERATORS
+    /* Init "Generator" string obj */
+    retval = string_new((uint8_t const **)&genstr, &pobj);
+    PM_RETURN_IF_ERROR(retval);
+    gVmGlobal.pgenStr = (pPmString_t)pobj;
+    
+    /* Init "next" string obj */
+    retval = string_new((uint8_t const **)&nextstr, &pobj);
+    PM_RETURN_IF_ERROR(retval);
+    gVmGlobal.pnextStr = (pPmString_t)pobj;
+#endif /* HAVE_GENERATORS */
+
+#ifdef HAVE_ASSERT
+    /* Init "Exception" string obj */
+    retval = string_new((uint8_t const **)&exnstr, &pobj);
+    PM_RETURN_IF_ERROR(retval);
+    gVmGlobal.pexnStr = (pPmString_t)pobj;
+#endif /* HAVE_ASSERT */
+
+#ifdef HAVE_BYTEARRAY
+    /* Init "bytearray" string obj */
+    retval = string_new((uint8_t const **)&pbastr, &pobj);
+    PM_RETURN_IF_ERROR(retval);
+    gVmGlobal.pbaStr = (pPmString_t)pobj;
+#endif /* HAVE_BYTEARRAY */
+
+    /* Init "__md" string obj */
+    retval = string_new((uint8_t const **)&pmdstr, &pobj);
+    PM_RETURN_IF_ERROR(retval);
+    gVmGlobal.pmdStr = (pPmString_t)pobj;
+
+    /* Init empty builtins */
+    gVmGlobal.builtins = C_NULL;
+
+    /* Init native frame */
+    gVmGlobal.nativeframe.od = sizeof(PmNativeFrame_t);
+    OBJ_SET_TYPE(&gVmGlobal.nativeframe, OBJ_TYPE_NFM);
+    gVmGlobal.nativeframe.nf_func = C_NULL;
+    gVmGlobal.nativeframe.nf_stack = C_NULL;
+    gVmGlobal.nativeframe.nf_active = C_FALSE;
+    gVmGlobal.nativeframe.nf_numlocals = 0;
+
+    /* Create empty threadList */
+    retval = list_new(&pobj);
+    gVmGlobal.threadList = (pPmList_t)pobj;
+
+    /* Init the PmImgPaths with std image info */
+    gVmGlobal.imgPaths.memspace[0] = MEMSPACE_PROG;
+    gVmGlobal.imgPaths.pimg[0] = (uint8_t *)&stdlib_img;
+    gVmGlobal.imgPaths.pathcount = 1;
+
+#ifdef HAVE_PRINT
+    gVmGlobal.needSoftSpace = C_FALSE;
+    gVmGlobal.somethingPrinted = C_FALSE;
+#endif /* HAVE_PRINT */
+
+    return retval;
+}
+
+
+PmReturn_t
+global_setBuiltins(pPmFunc_t pmod)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmObj_t pkey = C_NULL;
+    uint8_t const *pbistr = bistr;
+    uint8_t objid;
+
+    if (PM_PBUILTINS == C_NULL)
+    {
+        /* Need to load builtins first */
+        global_loadBuiltins();
+    }
+
+    /* Put builtins module in the module's attrs dict */
+    retval = string_new(&pbistr, &pkey);
+    PM_RETURN_IF_ERROR(retval);
+
+    heap_gcPushTempRoot(pkey, &objid);
+    retval = dict_setItem((pPmObj_t)pmod->f_attrs, pkey, PM_PBUILTINS);
+    heap_gcPopTempRoot(objid);
+
+    return retval;
+}
+
+
+PmReturn_t
+global_loadBuiltins(void)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmObj_t pkey = C_NULL;
+    uint8_t const *nonestr = (uint8_t const *)"None";
+    uint8_t const *falsestr = (uint8_t const *)"False";
+    uint8_t const *truestr = (uint8_t const *)"True";
+    pPmObj_t pstr = C_NULL;
+    pPmObj_t pbimod;
+    uint8_t const *pbistr = bistr;
+
+    /* Import the builtins */
+    retval = string_new(&pbistr, &pstr);
+    PM_RETURN_IF_ERROR(retval);
+    retval = mod_import(pstr, &pbimod);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Must interpret builtins' root code to set the attrs */
+    C_ASSERT(gVmGlobal.threadList->length == 0);
+    interp_addThread((pPmFunc_t)pbimod);
+    retval = interpret(INTERP_RETURN_ON_NO_THREADS);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Builtins points to the builtins module's attrs dict */
+    gVmGlobal.builtins = ((pPmFunc_t)pbimod)->f_attrs;
+
+    /* Set None manually */
+    retval = string_new(&nonestr, &pkey);
+    PM_RETURN_IF_ERROR(retval);
+    retval = dict_setItem(PM_PBUILTINS, pkey, PM_NONE);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Set False manually */
+    retval = string_new(&falsestr, &pkey);
+    PM_RETURN_IF_ERROR(retval);
+    retval = dict_setItem(PM_PBUILTINS, pkey, PM_FALSE);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Set True manually */
+    retval = string_new(&truestr, &pkey);
+    PM_RETURN_IF_ERROR(retval);
+    retval = dict_setItem(PM_PBUILTINS, pkey, PM_TRUE);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Deallocate builtins module */
+    retval = heap_freeChunk((pPmObj_t)pbimod);
+
+    return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/global.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,193 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __GLOBAL_H__
+#define __GLOBAL_H__
+
+
+/**
+ * \file
+ * \brief VM Globals
+ *
+ * VM globals header.
+ */
+
+
+/** The global root PmGlobals Dict object */
+#define PM_PBUILTINS    (pPmObj_t)(gVmGlobal.builtins)
+
+/** The global None object */
+#define PM_NONE         (pPmObj_t)(gVmGlobal.pnone)
+
+/** The global False object */
+#define PM_FALSE        (pPmObj_t)(gVmGlobal.pfalse)
+
+/** The global True object */
+#define PM_TRUE         (pPmObj_t)(gVmGlobal.ptrue)
+
+/** The global integer 0 object */
+#define PM_ZERO         (pPmObj_t)(gVmGlobal.pzero)
+
+/** The global integer 1 object */
+#define PM_ONE          (pPmObj_t)(gVmGlobal.pone)
+
+/** The global integer -1 object */
+#define PM_NEGONE       (pPmObj_t)(gVmGlobal.pnegone)
+
+/** The global string "code" */
+#define PM_CODE_STR     (pPmObj_t)(gVmGlobal.pcodeStr)
+
+#ifdef HAVE_CLASSES
+/** The global string "__init__" */
+#define PM_INIT_STR     (pPmObj_t)(gVmGlobal.pinitStr)
+#endif /* HAVE_CLASSES */
+
+#ifdef HAVE_GENERATORS
+/** The global string "Generator" */
+#define PM_GENERATOR_STR (pPmObj_t)(gVmGlobal.pgenStr)
+/** The global string "next" */
+#define PM_NEXT_STR (pPmObj_t)(gVmGlobal.pnextStr)
+#endif /* HAVE_GENERATORS */
+
+#ifdef HAVE_ASSERT
+/** The global string "Exception" */
+#define PM_EXCEPTION_STR (pPmObj_t)(gVmGlobal.pexnStr)
+#endif /* HAVE_ASSERT */
+
+#ifdef HAVE_BYTEARRAY
+/** The global string "bytearray" */
+#define PM_BYTEARRAY_STR (pPmObj_t)(gVmGlobal.pbaStr)
+#endif /* HAVE_BYTEARRAY */
+
+/** The global string "__md" */
+#define PM_MD_STR (pPmObj_t)(gVmGlobal.pmdStr)
+
+
+/**
+ * This struct contains ALL of PyMite's globals
+ */
+typedef struct PmVmGlobal_s
+{
+    /** Global none obj (none) */
+    pPmObj_t pnone;
+
+    /** Global integer 0 obj */
+    pPmInt_t pzero;
+
+    /** Global integer 1 obj */
+    pPmInt_t pone;
+
+    /** Global integer -1 obj */
+    pPmInt_t pnegone;
+
+    /** Global boolean False obj */
+    pPmInt_t pfalse;
+
+    /** Global boolean True obj */
+    pPmInt_t ptrue;
+
+    /** The string "code", used in interp.c RAISE_VARARGS */
+    pPmString_t pcodeStr;
+
+    /** Dict for builtins */
+    pPmDict_t builtins;
+
+    /** Paths to available images */
+    PmImgPaths_t imgPaths;
+
+    /** The single native frame.  Static alloc so it won't be GC'd */
+    PmNativeFrame_t nativeframe;
+
+    /** PyMite release value for when an error occurs */
+    uint8_t errVmRelease;
+
+    /** PyMite source file ID number for when an error occurs */
+    uint8_t errFileId;
+
+    /** Line number for when an error occurs */
+    uint16_t errLineNum;
+
+    /** Thread list */
+    pPmList_t threadList;
+
+    /** Ptr to current thread */
+    pPmThread_t pthread;
+
+#ifdef HAVE_CLASSES
+    /* NOTE: placing this field before the nativeframe field causes errors */
+    /** The string "__init__", used in interp.c CALL_FUNCTION */
+    pPmString_t pinitStr;
+#endif /* HAVE_CLASSES */
+
+#ifdef HAVE_GENERATORS
+    /** The string "Generator", used in interp.c CALL_FUNCTION */
+    pPmString_t pgenStr;
+    /** The string "next", used in interp.c FOR_ITER */
+    pPmString_t pnextStr;
+#endif /* HAVE_GENERATORS */
+
+#ifdef HAVE_ASSERT
+    /** The string "Exception", used in RAISE_VARARGS */
+    pPmString_t pexnStr;
+#endif /* HAVE_ASSERT */
+
+#ifdef HAVE_BYTEARRAY
+    /** The global string "bytearray" */
+    pPmString_t pbaStr;
+#endif /* HAVE_BYTEARRAY */
+
+    /** The global string "__md" */
+    pPmString_t pmdStr;
+
+#ifdef HAVE_PRINT
+    /** Remembers when a space is needed before printing the next object */
+    uint8_t needSoftSpace;
+    /** Remembers when something has printed since the last newline */
+    uint8_t somethingPrinted;
+#endif /* HAVE_PRINT */
+
+    /** Flag to trigger rescheduling */
+    uint8_t reschedule;
+} PmVmGlobal_t,
+ *pPmVmGlobal_t;
+
+
+extern volatile PmVmGlobal_t gVmGlobal;
+
+
+/**
+ * Initializes the global struct
+ *
+ * @return Return status
+ */
+PmReturn_t global_init(void);
+
+/**
+ * Sets the builtins dict into the given module's attrs.
+ *
+ * If not yet done, loads the "__bt" module via global_loadBuiltins().
+ * Restrictions described in that functions documentation apply.
+ *
+ * @param pmod Module whose attrs receive builtins
+ * @return Return status
+ */
+PmReturn_t global_setBuiltins(pPmFunc_t pmod);
+
+/**
+ * Loads the "__bt" module and sets the builtins dict (PM_PBUILTINS)
+ * to point to __bt's attributes dict.
+ * Creates "None" = None entry in builtins.
+ *
+ * When run, there should not be any other threads in the interpreter
+ * thread list yet.
+ *
+ * @return  Return status
+ */
+PmReturn_t global_loadBuiltins(void);
+
+#endif /* __GLOBAL_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/heap.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,1244 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x06
+
+
+/**
+ * \file
+ * \brief VM Heap
+ *
+ * VM heap operations.
+ * All of PyMite's dynamic memory is obtained from this heap.
+ * The heap provides dynamic memory on demand.
+ */
+
+
+#include "pm.h"
+
+
+/** The size of the temporary roots stack */
+#define HEAP_NUM_TEMP_ROOTS 24
+
+/**
+ * The maximum size a live chunk can be (a live chunk is one that is in use).
+ * The live chunk size is determined by the size field in the *object*
+ * descriptor.  That field is nine bits with two assumed lsbs (zeros):
+ * (0x1FF << 2) == 2044
+ */
+#ifdef PM_PLAT_POINTER_SIZE
+#if PM_PLAT_POINTER_SIZE == 8
+#define HEAP_MAX_LIVE_CHUNK_SIZE 2040
+#else
+#define HEAP_MAX_LIVE_CHUNK_SIZE 2044
+#endif
+#endif
+
+/**
+ * The maximum size a free chunk can be (a free chunk is one that is not in use).
+ * The free chunk size is limited by the size field in the *heap* descriptor.
+ * That field is fourteen bits with two assumed least significant bits (zeros):
+ * (0x3FFF << 2) == 65532
+ * For 64-bit platforms, the value is 4 bytes less so that a max-sized chunk is
+ * a multiple of 8, so that max-sized chunks created during heap_init() have a
+ * good boundary value.
+ */
+#ifdef PM_PLAT_POINTER_SIZE
+#if PM_PLAT_POINTER_SIZE == 8
+#define HEAP_MAX_FREE_CHUNK_SIZE 65528
+#else
+#define HEAP_MAX_FREE_CHUNK_SIZE 65532
+#endif
+#endif
+
+/** The minimum size a chunk can be
+ * (rounded up to a multiple of platform-pointer-size) */
+#ifdef PM_PLAT_POINTER_SIZE
+#if PM_PLAT_POINTER_SIZE == 8
+#define HEAP_MIN_CHUNK_SIZE ((sizeof(PmHeapDesc_t) + 7) & ~7)
+#else
+#define HEAP_MIN_CHUNK_SIZE ((sizeof(PmHeapDesc_t) + 3) & ~3)
+#endif
+#endif
+
+
+
+/**
+ * Gets the GC's mark bit for the object.
+ * This MUST NOT be called on objects that are free.
+ */
+#define OBJ_GET_GCVAL(pobj) (((pPmObj_t)pobj)->od & OD_MARK_MASK)
+
+/**
+ * Sets the GC's mark bit for the object
+ * This MUST NOT be called on objects that are free.
+ */
+#ifdef HAVE_GC
+#define OBJ_SET_GCVAL(pobj, gcval) \
+    do \
+    { \
+        ((pPmObj_t)pobj)->od = (gcval) ? ((pPmObj_t)pobj)->od | OD_MARK_MASK \
+                                       : ((pPmObj_t)pobj)->od & ~OD_MARK_MASK;\
+    } \
+    while (0)
+#else
+#define OBJ_SET_GCVAL(pobj, gcval)
+#endif /* HAVE_GC */
+
+#define CHUNK_GET_SIZE(pchunk) (((pPmHeapDesc_t)pchunk)->hd & HD_SIZE_MASK)
+
+/** Sets the size of the chunk in bytes. */
+#define CHUNK_SET_SIZE(pchunk, size) \
+    do \
+    { \
+        ((pPmHeapDesc_t)(pchunk))->hd &= ~HD_SIZE_MASK; \
+        ((pPmHeapDesc_t)(pchunk))->hd |= ((size) & HD_SIZE_MASK); \
+    } \
+    while (0)
+
+#define OBJ_SET_SIZE(pobj, size) \
+    do \
+    { \
+        ((pPmObj_t)pobj)->od &= ~OD_SIZE_MASK; \
+        ((pPmObj_t)pobj)->od |= ((size) & OD_SIZE_MASK); \
+    } \
+    while (0)
+
+
+/**
+ * The following is a diagram of the heap descriptor at the head of the chunk:
+ * @verbatim
+ *                MSb          LSb
+ *                7 6 5 4 3 2 1 0
+ *      pchunk-> +-+-+-+-+-+-+-+-+     S := Size of the chunk (2 LSbs dropped)
+ *               |     S     |F|R|     F := Chunk free bit (not in use)
+ *               +-----------+-+-+     R := Bit reserved for future use
+ *               |     S         |
+ *               +---------------+
+ *               |     P(L)      |     P := hd_prev: Pointer to previous node
+ *               |     P(H)      |     N := hd_next: Pointer to next node
+ *               |     N(L)      |
+ *               |     N(H)      |
+ *               +---------------+
+ *               | unused space  |
+ *               ...           ...
+ *               | end chunk     |
+ *               +---------------+
+ * @endverbatim
+ *
+ * On an 8-bit MCU with 16-bit addresses, the theoretical minimum size of the
+ * heap descriptor is 6 bytes.  The effective size (due to pointer alignment)
+ * is usually 8 bytes.  On an MCU with 32-bit addresses, the heap descriptor's
+ * size is 12 bytes.
+ */
+typedef struct PmHeapDesc_s
+{
+    /** Heap descriptor */
+    uint16_t hd;
+
+    /** Ptr to prev heap chunk */
+    struct PmHeapDesc_s *prev;
+
+    /** Ptr to next heap chunk */
+    struct PmHeapDesc_s *next;
+} PmHeapDesc_t,
+ *pPmHeapDesc_t;
+
+typedef struct PmHeap_s
+{
+    /** Pointer to base of heap.  Set at initialization of VM */
+    uint8_t *base;
+
+    /** Size of the heap.  Set at initialization of VM */
+    uint32_t size;
+
+    /** Ptr to list of free chunks; sorted smallest to largest. */
+    pPmHeapDesc_t pfreelist;
+
+    /** The amount of heap space available in free list */
+    uint32_t avail;
+
+#ifdef HAVE_GC
+    /** Garbage collection mark value */
+    uint8_t gcval;
+
+    /** Boolean to indicate if GC should run automatically */
+    uint8_t auto_gc;
+
+    /* #239: Fix GC when 2+ unlinked allocs occur */
+    /** Stack of objects to be held as temporary roots */
+    pPmObj_t temp_roots[HEAP_NUM_TEMP_ROOTS];
+
+    uint8_t temp_root_index;
+#endif                          /* HAVE_GC */
+
+} PmHeap_t,
+ *pPmHeap_t;
+
+
+/** The PyMite heap */
+static PmHeap_t pmHeap PM_PLAT_HEAP_ATTR;
+
+
+#if 0
+static void
+heap_gcPrintFreelist(void)
+{
+    pPmHeapDesc_t pchunk = pmHeap.pfreelist;
+
+    printf("DEBUG: pmHeap.avail = %d\n", pmHeap.avail);
+    printf("DEBUG: freelist:\n");
+    while (pchunk != C_NULL)
+    {
+        printf("DEBUG:     free chunk (%d bytes) @ 0x%0x\n",
+               CHUNK_GET_SIZE(pchunk), (int)pchunk);
+        pchunk = pchunk->next;
+    }
+}
+#endif
+
+
+#if 0
+/** DEBUG: dumps the heap and roots list to a file */
+static void
+heap_dump(void)
+{
+    static int n = 0;
+    uint16_t s;
+    uint32_t i;
+    char filename[17] = "pmheapdump0N.bin\0";
+    FILE *fp;
+
+    filename[11] = '0' + n++;
+    fp = fopen(filename, "wb");
+
+    /* magic : PMDUMP for little endian or PMUDMP for big endian */
+    fwrite(&"PM", 1, 2, fp);
+    s = 0x5544;
+    fwrite(&s, sizeof(uint16_t), 1, fp);
+    fwrite(&"MP", 1, 2, fp);
+
+    /* pointer size */
+    s = sizeof(intptr_t);
+    fwrite(&s, sizeof(uint16_t), 1, fp);
+
+    /* dump version */
+    s = 1;
+    fwrite(&s, sizeof(uint16_t), 1, fp);
+
+    /* pmfeatures */
+    s = 0;
+#ifdef USE_STRING_CACHE
+    s |= 1<<0;
+#endif
+#ifdef HAVE_DEFAULTARGS
+    s |= 1<<1;
+#endif
+#ifdef HAVE_CLOSURES
+    s |= 1<<2;
+#endif
+#ifdef HAVE_CLASSES
+    s |= 1<<3;
+#endif
+    fwrite(&s, sizeof(uint16_t), 1, fp);
+
+    /* Size of heap */
+    fwrite(&pmHeap.size, sizeof(uint32_t), 1, fp);
+
+    /* Write base address of heap */
+    fwrite((void*)&pmHeap.base, sizeof(intptr_t), 1, fp);
+
+    /* Write contents of heap */
+    fwrite(pmHeap.base, 1, pmHeap.size, fp);
+
+    /* Write num roots*/
+    i = 10;
+    fwrite(&i, sizeof(uint32_t), 1, fp);
+
+    /* Write heap root ptrs */
+    fwrite((void *)&gVmGlobal.pnone, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pfalse, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.ptrue, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pzero, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pone, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pnegone, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pcodeStr, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.builtins, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.nativeframe, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.threadList, sizeof(intptr_t), 1, fp);
+    fclose(fp);
+}
+#endif
+
+
+/* Removes the given chunk from the free list; leaves list in sorted order */
+static PmReturn_t
+heap_unlinkFromFreelist(pPmHeapDesc_t pchunk)
+{
+    C_ASSERT(pchunk != C_NULL);
+
+    pmHeap.avail -= CHUNK_GET_SIZE(pchunk);
+
+    if (pchunk->next != C_NULL)
+    {
+        pchunk->next->prev = pchunk->prev;
+    }
+
+    /* If pchunk was the first chunk in the free list, update the heap ptr */
+    if (pchunk->prev == C_NULL)
+    {
+        pmHeap.pfreelist = pchunk->next;
+    }
+    else
+    {
+        pchunk->prev->next = pchunk->next;
+    }
+
+    return PM_RET_OK;
+}
+
+
+/* Inserts in order a chunk into the free list.  Caller adjusts heap state */
+static PmReturn_t
+heap_linkToFreelist(pPmHeapDesc_t pchunk)
+{
+    uint16_t size;
+    pPmHeapDesc_t pscan;
+
+    /* Ensure the object is already free */
+    C_ASSERT(OBJ_GET_FREE(pchunk) != 0);
+
+    pmHeap.avail += CHUNK_GET_SIZE(pchunk);
+
+    /* If free list is empty, add to head of list */
+    if (pmHeap.pfreelist == C_NULL)
+    {
+        pmHeap.pfreelist = pchunk;
+        pchunk->next = C_NULL;
+        pchunk->prev = C_NULL;
+
+        return PM_RET_OK;
+    }
+
+    /* Scan free list for insertion point */
+    pscan = pmHeap.pfreelist;
+    size = CHUNK_GET_SIZE(pchunk);
+    while ((CHUNK_GET_SIZE(pscan) < size) && (pscan->next != C_NULL))
+    {
+        pscan = pscan->next;
+    }
+
+    /*
+     * Insert chunk after the scan chunk (next is NULL).
+     * This is a slightly rare case where the last chunk in the free list
+     * is smaller than the chunk being freed.
+     */
+    if (size > CHUNK_GET_SIZE(pscan))
+    {
+        pchunk->next = pscan->next;
+        pscan->next = pchunk;
+        pchunk->prev = pscan;
+    }
+
+    /* Insert chunk before the scan chunk */
+    else
+    {
+        pchunk->next = pscan;
+        pchunk->prev = pscan->prev;
+
+        /* If chunk will be first item in free list */
+        if (pscan->prev == C_NULL)
+        {
+            pmHeap.pfreelist = pchunk;
+        }
+        else
+        {
+            pscan->prev->next = pchunk;
+        }
+        pscan->prev = pchunk;
+    }
+
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+heap_init(uint8_t *base, uint32_t size)
+{
+    pPmHeapDesc_t pchunk;
+    uint32_t hs;
+    uint8_t *adjbase;
+
+    /* Round-up Heap base by the size of the platform pointer */
+    adjbase = base + ((sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1));
+    pmHeap.base = adjbase;
+    pmHeap.size = size - (adjbase - base);
+
+#if __DEBUG__
+    /* Fill the heap with a non-NULL value to bring out any heap bugs. */
+    sli_memset(pmHeap.base, 0xAA, pmHeap.size);
+#endif
+
+    /* Init heap globals */
+    pmHeap.pfreelist = C_NULL;
+    pmHeap.avail = 0;
+#ifdef HAVE_GC
+    pmHeap.gcval = (uint8_t)0;
+    pmHeap.temp_root_index = (uint8_t)0;
+    heap_gcSetAuto(C_TRUE);
+#endif /* HAVE_GC */
+
+    pchunk = (pPmHeapDesc_t)pmHeap.base;
+    hs = pmHeap.size;
+
+    /* #180 Proactively link memory previously lost/neglected at tail of heap */
+    if ((hs % HEAP_MAX_FREE_CHUNK_SIZE) < HEAP_MIN_CHUNK_SIZE)
+    {
+        OBJ_SET_FREE(pchunk, 1);
+        CHUNK_SET_SIZE(pchunk, HEAP_MIN_CHUNK_SIZE);
+        heap_linkToFreelist(pchunk);
+        hs -= HEAP_MIN_CHUNK_SIZE;
+        pchunk = (pPmHeapDesc_t)((uint8_t *)pchunk + HEAP_MIN_CHUNK_SIZE);
+    }
+
+    /* Create as many max-sized chunks as possible in the freelist */
+    for (;
+         hs >= HEAP_MAX_FREE_CHUNK_SIZE; hs -= HEAP_MAX_FREE_CHUNK_SIZE)
+    {
+        OBJ_SET_FREE(pchunk, 1);
+        CHUNK_SET_SIZE(pchunk, HEAP_MAX_FREE_CHUNK_SIZE);
+        heap_linkToFreelist(pchunk);
+        pchunk = (pPmHeapDesc_t)((uint8_t *)pchunk + HEAP_MAX_FREE_CHUNK_SIZE);
+    }
+
+    /* Add any leftover memory to the freelist */
+    if (hs >= HEAP_MIN_CHUNK_SIZE)
+    {
+        /* Round down to a multiple of four */
+        hs = hs & ~3;
+        OBJ_SET_FREE(pchunk, 1);
+        CHUNK_SET_SIZE(pchunk, hs);
+        heap_linkToFreelist(pchunk);
+    }
+
+    C_DEBUG_PRINT(VERBOSITY_LOW, "heap_init(), id=%p, s=%u\n",
+                  pmHeap.base, (unsigned int)pmHeap.avail);
+
+#if USE_STRING_CACHE
+    string_cacheInit();
+#endif
+
+    return PM_RET_OK;
+}
+
+
+/**
+ * Obtains a chunk of memory from the free list
+ *
+ * Performs the Best Fit algorithm.
+ * Iterates through the freelist to see if a chunk of suitable size exists.
+ * Shaves a chunk to perfect size iff the remainder is greater than
+ * the minimum chunk size.
+ *
+ * @param size Requested chunk size
+ * @param r_pchunk Return ptr to chunk
+ * @return Return status
+ */
+static PmReturn_t
+heap_getChunkImpl(uint16_t size, uint8_t **r_pchunk)
+{
+    PmReturn_t retval;
+    pPmHeapDesc_t pchunk;
+    pPmHeapDesc_t premainderChunk;
+
+    C_ASSERT(r_pchunk != C_NULL);
+
+    /* Skip to the first chunk that can hold the requested size */
+    pchunk = pmHeap.pfreelist;
+    while ((pchunk != C_NULL) && (CHUNK_GET_SIZE(pchunk) < size))
+    {
+        pchunk = pchunk->next;
+    }
+
+    /* No chunk of appropriate size was found, raise OutOfMemory exception */
+    if (pchunk == C_NULL)
+    {
+        *r_pchunk = C_NULL;
+        PM_RAISE(retval, PM_RET_EX_MEM);
+        return retval;
+    }
+
+    /* Remove the chunk from the free list */
+    retval = heap_unlinkFromFreelist(pchunk);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Check if a chunk should be carved from what is available */
+    if (CHUNK_GET_SIZE(pchunk) - size >= HEAP_MIN_CHUNK_SIZE)
+    {
+        /* Create the heap descriptor for the remainder chunk */
+        premainderChunk = (pPmHeapDesc_t)((uint8_t *)pchunk + size);
+        OBJ_SET_FREE(premainderChunk, 1);
+        CHUNK_SET_SIZE(premainderChunk, CHUNK_GET_SIZE(pchunk) - size);
+
+        /* Put the remainder chunk back in the free list */
+        retval = heap_linkToFreelist(premainderChunk);
+        PM_RETURN_IF_ERROR(retval);
+
+        /* Convert the chunk from a heap descriptor to an object descriptor */
+        OBJ_SET_SIZE(pchunk, 0);
+        OBJ_SET_FREE(pchunk, 0);
+        OBJ_SET_SIZE(pchunk, size);
+
+        C_DEBUG_PRINT(VERBOSITY_HIGH,
+                      "heap_getChunkImpl()carved, id=%p, s=%d\n", pchunk,
+                      size);
+    }
+    else
+    {
+        /* Set chunk's type to none (overwrites size field's high byte) */
+        OBJ_SET_TYPE((pPmObj_t)pchunk, OBJ_TYPE_NON);
+        OBJ_SET_FREE(pchunk, 0);
+
+        C_DEBUG_PRINT(VERBOSITY_HIGH,
+                      "heap_getChunkImpl()exact, id=%p, s=%d\n", pchunk,
+                      PM_OBJ_GET_SIZE(pchunk));
+    }
+
+    /*
+     * Set the chunk's GC mark so it will be collected during the next GC cycle
+     * if it is not reachable
+     */
+    OBJ_SET_GCVAL(pchunk, pmHeap.gcval);
+
+    /* Return the chunk */
+    *r_pchunk = (uint8_t *)pchunk;
+
+    return retval;
+}
+
+
+/*
+ * Allocates chunk of memory.
+ * Filters out invalid sizes.
+ * Rounds the size up to the next multiple of the platform pointer size.
+ * Obtains a chunk of at least the desired size.
+ */
+PmReturn_t
+heap_getChunk(uint16_t requestedsize, uint8_t **r_pchunk)
+{
+    PmReturn_t retval;
+    uint16_t adjustedsize;
+
+    /* Ensure size request is valid */
+    if (requestedsize > HEAP_MAX_LIVE_CHUNK_SIZE)
+    {
+        PM_RAISE(retval, PM_RET_EX_MEM);
+        return retval;
+    }
+
+    else if (requestedsize < HEAP_MIN_CHUNK_SIZE)
+    {
+        requestedsize = HEAP_MIN_CHUNK_SIZE;
+    }
+
+    /*
+     * Round up the size to a multiple of N bytes,
+     * where N is 8 for 64-bit platforms and 4 for all else.
+     * This maintains pointer alignment in the heap (required).
+     */
+#ifdef PM_PLAT_POINTER_SIZE
+#if PM_PLAT_POINTER_SIZE == 8
+    adjustedsize = ((requestedsize + 7) & ~7);
+#else
+    adjustedsize = ((requestedsize + 3) & ~3);
+#endif /* PM_PLAT_POINTER_SIZE */
+#else
+    adjustedsize = ((requestedsize + 3) & ~3);
+#endif /* PM_PLAT_POINTER_SIZE */
+
+    /* Attempt to get a chunk */
+    retval = heap_getChunkImpl(adjustedsize, r_pchunk);
+
+#ifdef HAVE_GC
+    /* Perform GC if out of memory, gc is enabled and not in native session */
+    if ((retval == PM_RET_EX_MEM) && (pmHeap.auto_gc == C_TRUE)
+        && (gVmGlobal.nativeframe.nf_active == C_FALSE))
+    {
+        retval = heap_gcRun();
+        PM_RETURN_IF_ERROR(retval);
+
+        /* Attempt to get a chunk */
+        retval = heap_getChunkImpl(adjustedsize, r_pchunk);
+    }
+#endif /* HAVE_GC */
+
+    /* Ensure that the pointer is N-byte aligned */
+    if (retval == PM_RET_OK)
+    {
+#ifdef PM_PLAT_POINTER_SIZE
+#if PM_PLAT_POINTER_SIZE == 8
+        C_ASSERT(((intptr_t)*r_pchunk & 7) == 0);
+#else
+        C_ASSERT(((intptr_t)*r_pchunk & 3) == 0);
+#endif /* PM_PLAT_POINTER_SIZE */
+#else
+        C_ASSERT(((intptr_t)*r_pchunk & 3) == 0);
+#endif /* PM_PLAT_POINTER_SIZE */
+    }
+
+    return retval;
+}
+
+
+/* Releases chunk to the free list */
+PmReturn_t
+heap_freeChunk(pPmObj_t ptr)
+{
+    PmReturn_t retval;
+
+    C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_freeChunk(), id=%p, s=%d\n",
+                  ptr, PM_OBJ_GET_SIZE(ptr));
+
+    /* Ensure the chunk falls within the heap */
+    C_ASSERT(((uint8_t *)ptr >= &pmHeap.base[0])
+              && ((uint8_t *)ptr <= &pmHeap.base[pmHeap.size]));
+
+    /* Insert the chunk into the freelist */
+    OBJ_SET_FREE(ptr, 1);
+
+    /* Clear type so that heap descriptor's size's upper byte is zero */
+    OBJ_SET_TYPE(ptr, 0);
+    retval = heap_linkToFreelist((pPmHeapDesc_t)ptr);
+    PM_RETURN_IF_ERROR(retval);
+
+    return retval;
+}
+
+
+uint32_t
+heap_getAvail(void)
+{
+    return pmHeap.avail;
+}
+
+
+uint32_t
+heap_getSize(void)
+{
+    return pmHeap.size;
+}
+
+
+#ifdef HAVE_GC
+/*
+ * Marks the given object and the objects it references.
+ *
+ * @param   pobj Any non-free heap object
+ * @return  Return code
+ */
+static PmReturn_t
+heap_gcMarkObj(pPmObj_t pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t i = 0;
+    int16_t n;
+    PmType_t type;
+
+    /* Return if ptr is null or object is already marked */
+    if (pobj == C_NULL)
+    {
+        return retval;
+    }
+    if (OBJ_GET_GCVAL(pobj) == pmHeap.gcval)
+    {
+        return retval;
+    }
+
+    /* The pointer must be within the heap (native frame is special case) */
+    C_ASSERT((((uint8_t *)pobj >= &pmHeap.base[0])
+              && ((uint8_t *)pobj <= &pmHeap.base[pmHeap.size]))
+             || ((uint8_t *)pobj == (uint8_t *)&gVmGlobal.nativeframe));
+
+    /* The object must not already be free */
+    C_ASSERT(OBJ_GET_FREE(pobj) == 0);
+
+    type = (PmType_t)OBJ_GET_TYPE(pobj);
+    switch (type)
+    {
+        /* Objects with no references to other objects */
+        case OBJ_TYPE_NON:
+        case OBJ_TYPE_INT:
+        case OBJ_TYPE_FLT:
+        case OBJ_TYPE_STR:
+        case OBJ_TYPE_NOB:
+        case OBJ_TYPE_BOOL:
+        case OBJ_TYPE_CIO:
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+            break;
+
+        case OBJ_TYPE_TUP:
+            i = ((pPmTuple_t)pobj)->length;
+
+            /* Mark tuple head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark each obj in tuple */
+            while (--i >= 0)
+            {
+                retval = heap_gcMarkObj(((pPmTuple_t)pobj)->val[i]);
+                PM_RETURN_IF_ERROR(retval);
+            }
+            break;
+
+        case OBJ_TYPE_LST:
+
+            /* Mark the list */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the seglist */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmList_t)pobj)->val);
+            break;
+
+        case OBJ_TYPE_DIC:
+            /* Mark the dict head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the keys seglist */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_keys);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the vals seglist */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_vals);
+            break;
+
+        case OBJ_TYPE_COB:
+            /* Mark the code obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the names tuple */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_names);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the consts tuple */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_consts);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* #122: Mark the code image if it is in RAM */
+            if (((pPmCo_t)pobj)->co_memspace == MEMSPACE_RAM)
+            {
+                retval = heap_gcMarkObj((pPmObj_t)
+                                        (((pPmCo_t)pobj)->co_codeimgaddr));
+                PM_RETURN_IF_ERROR(retval);
+            }
+
+#ifdef HAVE_CLOSURES
+            /* #256: Add support for closures */
+            /* Mark the cellvars tuple */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_cellvars);
+#endif /* HAVE_CLOSURES */
+            break;
+
+        case OBJ_TYPE_MOD:
+        case OBJ_TYPE_FXN:
+            /* Module and Func objs are implemented via the PmFunc_t */
+            /* Mark the func obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the code obj */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_co);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the attr dict */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_attrs);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the globals dict */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_globals);
+            PM_RETURN_IF_ERROR(retval);
+
+#ifdef HAVE_DEFAULTARGS
+            /* Mark the default args tuple */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_defaultargs);
+            PM_RETURN_IF_ERROR(retval);
+#endif /* HAVE_DEFAULTARGS */
+
+#ifdef HAVE_CLOSURES
+            /* #256: Mark the closure tuple */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_closure);
+#endif /* HAVE_CLOSURES */
+            break;
+
+#ifdef HAVE_CLASSES
+        case OBJ_TYPE_CLI:
+            /* Mark the obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the class */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_class);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the attrs dict */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs);
+            break;
+
+        case OBJ_TYPE_MTH:
+            /* Mark the obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the instance */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_instance);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the func */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_func);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the attrs dict */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_attrs);
+            break;
+
+        case OBJ_TYPE_CLO:
+            /* Mark the obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the attrs dict */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_attrs);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the base tuple */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_bases);
+            break;
+#endif /* HAVE_CLASSES */
+
+        /*
+         * An obj in ram should not be of these types.
+         * Images arrive in RAM as string objects (image is array of bytes)
+         */
+        case OBJ_TYPE_CIM:
+        case OBJ_TYPE_NIM:
+            PM_RAISE(retval, PM_RET_EX_SYS);
+            return retval;
+
+        case OBJ_TYPE_FRM:
+        {
+            pPmObj_t *ppobj2 = C_NULL;
+
+            /* Mark the frame obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the previous frame, if this isn't a generator's frame */
+            /* Issue #129: Fix iterator losing its object */
+            if ((((pPmFrame_t)pobj)->fo_func->f_co->co_flags & CO_GENERATOR) == 0)
+            {
+                retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_back);
+                PM_RETURN_IF_ERROR(retval);
+            }
+
+            /* Mark the fxn obj */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_func);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the blockstack */
+            retval = heap_gcMarkObj((pPmObj_t)
+                                    ((pPmFrame_t)pobj)->fo_blockstack);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the attrs dict */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_attrs);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark the globals dict */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_globals);
+            PM_RETURN_IF_ERROR(retval);
+
+            /* Mark each obj in the locals list and the stack */
+            ppobj2 = ((pPmFrame_t)pobj)->fo_locals;
+            while (ppobj2 < ((pPmFrame_t)pobj)->fo_sp)
+            {
+                retval = heap_gcMarkObj(*ppobj2);
+                PM_RETURN_IF_ERROR(retval);
+                ppobj2++;
+            }
+            break;
+        }
+
+        case OBJ_TYPE_BLK:
+            /* Mark the block obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the next block in the stack */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmBlock_t)pobj)->next);
+            break;
+
+        case OBJ_TYPE_SGL:
+            /* Mark the seglist obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the seglist's segments */
+            n = ((pSeglist_t)pobj)->sl_length;
+            pobj = (pPmObj_t)((pSeglist_t)pobj)->sl_rootseg;
+            for (i = 0; i < n; i++)
+            {
+                /* Mark the segment item */
+                retval = heap_gcMarkObj(((pSegment_t)pobj)->s_val[i % SEGLIST_OBJS_PER_SEG]);
+                PM_RETURN_IF_ERROR(retval);
+
+                /* Mark the segment obj head */
+                if ((i % SEGLIST_OBJS_PER_SEG) == 0)
+                {
+                    OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+                }
+
+                /* Point to the next segment */
+                else
+                if ((i % SEGLIST_OBJS_PER_SEG) == (SEGLIST_OBJS_PER_SEG - 1))
+                {
+                    pobj = (pPmObj_t)((pSegment_t)pobj)->next;
+                    if (pobj == C_NULL)
+                    {
+                        break;
+                    }
+                }
+            }
+            break;
+
+        case OBJ_TYPE_SQI:
+            /* Mark the sequence iterator obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the sequence */
+            retval = heap_gcMarkObj(((pPmSeqIter_t)pobj)->si_sequence);
+            break;
+
+        case OBJ_TYPE_THR:
+            /* Mark the thread obj head */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the current frame */
+            retval = heap_gcMarkObj((pPmObj_t)((pPmThread_t)pobj)->pframe);
+            break;
+
+        case OBJ_TYPE_NFM:
+            /*
+             * Mark the obj desc.  This doesn't really do much since the
+             * native frame is declared static (not from the heap), but this
+             * is here in case that ever changes
+             */
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            /* Mark the native frame's remaining fields if active */
+            if (gVmGlobal.nativeframe.nf_active)
+            {
+                /* Mark the frame stack */
+                retval = heap_gcMarkObj((pPmObj_t)
+                                        gVmGlobal.nativeframe.nf_back);
+                PM_RETURN_IF_ERROR(retval);
+
+                /* Mark the function object */
+                retval = heap_gcMarkObj((pPmObj_t)
+                                        gVmGlobal.nativeframe.nf_func);
+                PM_RETURN_IF_ERROR(retval);
+
+                /* Mark the stack object */
+                retval = heap_gcMarkObj(gVmGlobal.nativeframe.nf_stack);
+                PM_RETURN_IF_ERROR(retval);
+
+                /* Mark the args to the native func */
+                for (i = 0; i < NATIVE_GET_NUM_ARGS(); i++)
+                {
+                    retval =
+                        heap_gcMarkObj(gVmGlobal.nativeframe.nf_locals[i]);
+                    PM_RETURN_IF_ERROR(retval);
+                }
+            }
+            break;
+
+#ifdef HAVE_BYTEARRAY
+        case OBJ_TYPE_BYA:
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+
+            retval = heap_gcMarkObj((pPmObj_t)((pPmBytearray_t)pobj)->val);
+            break;
+
+        case OBJ_TYPE_BYS:
+            OBJ_SET_GCVAL(pobj, pmHeap.gcval);
+            break;
+#endif /* HAVE_BYTEARRAY */
+
+        default:
+            /* There should be no invalid types */
+            PM_RAISE(retval, PM_RET_EX_SYS);
+            break;
+    }
+    return retval;
+}
+
+
+/*
+ * Marks the root objects so they won't be collected during the sweep phase.
+ * Recursively marks all objects reachable from the roots.
+ */
+static PmReturn_t
+heap_gcMarkRoots(void)
+{
+    PmReturn_t retval;
+    uint8_t i;
+
+    /* Toggle the GC marking value so it differs from the last run */
+    pmHeap.gcval ^= 1;
+
+    /* Mark the constant objects */
+    retval = heap_gcMarkObj(PM_NONE);
+    PM_RETURN_IF_ERROR(retval);
+    retval = heap_gcMarkObj(PM_FALSE);
+    PM_RETURN_IF_ERROR(retval);
+    retval = heap_gcMarkObj(PM_TRUE);
+    PM_RETURN_IF_ERROR(retval);
+    retval = heap_gcMarkObj(PM_ZERO);
+    PM_RETURN_IF_ERROR(retval);
+    retval = heap_gcMarkObj(PM_ONE);
+    PM_RETURN_IF_ERROR(retval);
+    retval = heap_gcMarkObj(PM_NEGONE);
+    PM_RETURN_IF_ERROR(retval);
+    retval = heap_gcMarkObj(PM_CODE_STR);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Mark the builtins dict */
+    retval = heap_gcMarkObj(PM_PBUILTINS);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Mark the native frame if it is active */
+    retval = heap_gcMarkObj((pPmObj_t)&gVmGlobal.nativeframe);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Mark the thread list */
+    retval = heap_gcMarkObj((pPmObj_t)gVmGlobal.threadList);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Mark the temporary roots */
+    for (i = 0; i < pmHeap.temp_root_index; i++)
+    {
+        retval = heap_gcMarkObj(pmHeap.temp_roots[i]);
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    return retval;
+}
+
+
+#if USE_STRING_CACHE
+/**
+ * Unlinks free objects from the string cache.
+ * This function must only be called by the GC after the heap has been marked
+ * and before the heap has been swept.
+ *
+ * This solves the problem where a string object would be collected
+ * but its chunk was still linked into the free list
+ *
+ * @param gcval The current value for chunks marked by the GC
+ */
+static PmReturn_t
+heap_purgeStringCache(uint8_t gcval)
+{
+    PmReturn_t retval;
+    pPmString_t *ppstrcache;
+    pPmString_t pstr;
+
+    /* Update string cache pointer if the first string objs are not marked */
+    retval = string_getCache(&ppstrcache);
+    if (ppstrcache == C_NULL)
+    {
+        return retval;
+    }
+    while ((*ppstrcache != C_NULL) && (OBJ_GET_GCVAL(*ppstrcache) != gcval))
+    {
+        *ppstrcache = (*ppstrcache)->next;
+    }
+    if (*ppstrcache == C_NULL)
+    {
+        return retval;
+    }
+
+    /* Unlink remaining strings that are not marked */
+    for (pstr = *ppstrcache; pstr->next != C_NULL;)
+    {
+        /* Unlink consecutive non-marked strings */
+        while ((pstr->next != C_NULL) && (OBJ_GET_GCVAL(pstr->next) != gcval))
+        {
+            pstr->next = pstr->next->next;
+        }
+
+        /* If not at end of cache, string must be marked, skip it */
+        if (pstr->next != C_NULL)
+        {
+            pstr = pstr->next;
+        }
+    }
+
+    return retval;
+}
+#endif
+
+
+/*
+ * Reclaims any object that does not have a current mark.
+ * Puts it in the free list.  Coalesces all contiguous free chunks.
+ */
+static PmReturn_t
+heap_gcSweep(void)
+{
+    PmReturn_t retval;
+    pPmObj_t pobj;
+    pPmHeapDesc_t pchunk;
+    uint16_t totalchunksize;
+
+#if USE_STRING_CACHE
+    retval = heap_purgeStringCache(pmHeap.gcval);
+#endif
+
+    /* Start at the base of the heap */
+    pobj = (pPmObj_t)pmHeap.base;
+    while ((uint8_t *)pobj < &pmHeap.base[pmHeap.size])
+    {
+        /* Skip to the next unmarked or free chunk within the heap */
+        while (!OBJ_GET_FREE(pobj)
+               && (OBJ_GET_GCVAL(pobj) == pmHeap.gcval)
+               && ((uint8_t *)pobj < &pmHeap.base[pmHeap.size]))
+        {
+            pobj = (pPmObj_t)((uint8_t *)pobj + PM_OBJ_GET_SIZE(pobj));
+        }
+
+        /* Stop if reached the end of the heap */
+        if ((uint8_t *)pobj >= &pmHeap.base[pmHeap.size])
+        {
+            break;
+        }
+
+        /* Accumulate the sizes of all consecutive unmarked or free chunks */
+        totalchunksize = 0;
+
+        /* Coalesce all contiguous free chunks */
+        pchunk = (pPmHeapDesc_t)pobj;
+        while (OBJ_GET_FREE(pchunk)
+               || (!OBJ_GET_FREE(pchunk)
+                   && (OBJ_GET_GCVAL(pchunk) != pmHeap.gcval)))
+        {
+            /*
+             * If the chunk is already free, unlink it because its size
+             * is about to change
+             */
+            if (OBJ_GET_FREE(pchunk))
+            {
+                if ((totalchunksize + CHUNK_GET_SIZE(pchunk))
+                    > HEAP_MAX_FREE_CHUNK_SIZE)
+                {
+                    break;
+                }
+                retval = heap_unlinkFromFreelist(pchunk);
+                PM_RETURN_IF_ERROR(retval);
+            }
+
+            /* Otherwise free and reclaim the unmarked chunk */
+            else
+            {
+                if ((totalchunksize + PM_OBJ_GET_SIZE(pchunk))
+                    > HEAP_MAX_FREE_CHUNK_SIZE)
+                {
+                    break;
+                }
+                OBJ_SET_TYPE(pchunk, 0);
+                OBJ_SET_FREE(pchunk, 1);
+            }
+            totalchunksize = totalchunksize + CHUNK_GET_SIZE(pchunk);
+
+            C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_gcSweep(), id=%p, s=%d\n",
+                          pchunk, CHUNK_GET_SIZE(pchunk));
+
+            /* Proceed to the next chunk */
+            pchunk = (pPmHeapDesc_t)
+                ((uint8_t *)pchunk + CHUNK_GET_SIZE(pchunk));
+
+            /* Stop if it's past the end of the heap */
+            if ((uint8_t *)pchunk >= &pmHeap.base[pmHeap.size])
+            {
+                break;
+            }
+        }
+
+        /* Set the heap descriptor data */
+        OBJ_SET_FREE(pobj, 1);
+        CHUNK_SET_SIZE(pobj, totalchunksize);
+
+        /* Insert chunk into free list */
+        retval = heap_linkToFreelist((pPmHeapDesc_t)pobj);
+        PM_RETURN_IF_ERROR(retval);
+
+        /* Continue to the next chunk */
+        pobj = (pPmObj_t)pchunk;
+    }
+
+    return PM_RET_OK;
+}
+
+
+/* Runs the mark-sweep garbage collector */
+PmReturn_t
+heap_gcRun(void)
+{
+    PmReturn_t retval;
+
+    /* #239: Fix GC when 2+ unlinked allocs occur */
+    /* This assertion fails when there are too many objects on the temporary
+     * root stack and a GC occurs; consider increasing PM_HEAP_NUM_TEMP_ROOTS
+     */
+    C_ASSERT(pmHeap.temp_root_index < HEAP_NUM_TEMP_ROOTS);
+
+    C_DEBUG_PRINT(VERBOSITY_LOW, "heap_gcRun()\n");
+
+    retval = heap_gcMarkRoots();
+    PM_RETURN_IF_ERROR(retval);
+
+    /*heap_dump();*/
+    retval = heap_gcSweep();
+    /*heap_dump();*/
+    return retval;
+}
+
+
+/* Enables or disables automatic garbage collection */
+PmReturn_t
+heap_gcSetAuto(uint8_t auto_gc)
+{
+    pmHeap.auto_gc = auto_gc;
+    return PM_RET_OK;
+}
+
+void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid)
+{
+    if (pmHeap.temp_root_index < HEAP_NUM_TEMP_ROOTS)
+    {
+        *r_objid = pmHeap.temp_root_index;
+        pmHeap.temp_roots[pmHeap.temp_root_index] = pobj;
+        pmHeap.temp_root_index++;
+    }
+    return;
+}
+
+
+void heap_gcPopTempRoot(uint8_t objid)
+{
+    pmHeap.temp_root_index = objid;
+}
+
+#else
+
+void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid) {}
+void heap_gcPopTempRoot(uint8_t objid) {}
+
+#endif /* HAVE_GC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/heap.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,106 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __HEAP_H__
+#define __HEAP_H__
+
+
+/**
+ * \file
+ * \brief VM Heap
+ *
+ * VM heap header.
+ */
+
+
+/**
+ * The threshold of heap.avail under which the interpreter will run the GC
+ * just before starting a native session.
+ */
+#define HEAP_GC_NF_THRESHOLD (512)
+
+
+#ifdef __DEBUG__
+#define DEBUG_PRINT_HEAP_AVAIL(s) \
+    do { uint16_t n; heap_getAvail(&n); printf(s "heap avail = %d\n", n); } \
+    while (0)
+#else
+#define DEBUG_PRINT_HEAP_AVAIL(s)
+#endif
+
+
+/**
+ * Initializes the heap for use.
+ *
+ * @param base The address where the contiguous heap begins
+ * @param size The size in bytes (octets) of the given heap.
+ * @return  Return code.
+ */
+PmReturn_t heap_init(uint8_t *base, uint32_t size);
+
+/**
+ * Returns a free chunk from the heap.
+ *
+ * The chunk will be at least the requested size.
+ * The actual size can be found in the return chunk's od.od_size.
+ *
+ * @param   requestedsize Requested size of the chunk in bytes.
+ * @param   r_pchunk Addr of ptr to chunk (return).
+ * @return  Return code
+ */
+PmReturn_t heap_getChunk(uint16_t requestedsize, uint8_t **r_pchunk);
+
+/**
+ * Places the chunk back in the heap.
+ *
+ * @param   ptr Pointer to object to free.
+ */
+PmReturn_t heap_freeChunk(pPmObj_t ptr);
+
+/** @return  Return number of bytes available in the heap */
+uint32_t heap_getAvail(void);
+
+/** @return  Return the size of the heap in bytes */
+uint32_t heap_getSize(void);
+
+#ifdef HAVE_GC
+/**
+ * Runs the mark-sweep garbage collector
+ *
+ * @return  Return code
+ */
+PmReturn_t heap_gcRun(void);
+
+/**
+ * Enables (if true) or disables automatic garbage collection
+ *
+ * @param   bool Value to enable or disable auto GC
+ * @return  Return code
+ */
+PmReturn_t heap_gcSetAuto(uint8_t auto_gc);
+
+#endif /* HAVE_GC */
+
+/**
+ * Pushes an object onto the temporary roots stack if there is room
+ * to protect the objects from a potential garbage collection
+ *
+ * @param pobj Object to push onto the roots stack
+ * @param r_objid By reference; ID to use when popping the object from the stack
+ */
+void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid);
+
+/**
+ * Pops from the temporary roots stack all objects upto and including the one
+ * denoted by the given ID 
+ *
+ * @param objid ID of object to pop
+ */
+void heap_gcPopTempRoot(uint8_t objid);
+
+#endif /* __HEAP_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/img.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,147 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x07
+
+
+/**
+ * \file
+ * \brief Image routines
+ *
+ * Created to eliminate a circular include
+ * among mem, string and obj.
+ */
+
+
+#include "pm.h"
+
+
+/*
+ * Searches for a module's name in a contiguous array of images
+ * in the given namespace starting at the given address.
+ * A module's name is stored in the last index of the names tuple of an image.
+ */
+static PmReturn_t
+img_findInPath(uint8_t *cname, uint16_t cnamelen, PmMemSpace_t memspace,
+               uint8_t const **paddr)
+{
+    uint8_t const *imgtop;
+    PmType_t type;
+    uint16_t len;
+    int16_t size = 0;
+    uint8_t i = 0;
+
+    /* Addr is top of img */
+    imgtop = *paddr;
+
+    /* Get img's type byte */
+    type = (PmType_t)mem_getByte(memspace, paddr);
+
+    /* Search all sequential images */
+    while (type == OBJ_TYPE_CIM)
+    {
+        /* Use size field to calc addr of next potential img */
+        size = mem_getWord(memspace, paddr);
+
+        /* Point to names tuple */
+        *paddr = imgtop + CI_NAMES_FIELD;
+
+        /* Ensure it's a tuple */
+        type = (PmType_t)mem_getByte(memspace, paddr);
+        C_ASSERT(type == OBJ_TYPE_TUP);
+
+        /* Scan to last name in tuple (it's the module's name) */
+        i = mem_getByte(memspace, paddr) - (uint8_t)1;
+        for (; i > 0; i--)
+        {
+            /* Ensure obj is a string */
+            type = (PmType_t)mem_getByte(memspace, paddr);
+            C_ASSERT(type == OBJ_TYPE_STR);
+
+            /* Skip the length of the string */
+            len = mem_getWord(memspace, paddr);
+            (*paddr) += len;
+        }
+
+        /* Ensure it's a string */
+        type = (PmType_t)mem_getByte(memspace, paddr);
+        C_ASSERT(type == OBJ_TYPE_STR);
+
+        /* If strings match, return the address of this image */
+        if ((cnamelen == mem_getWord(memspace, paddr))
+            && (PM_RET_OK == mem_cmpn(cname, cnamelen, memspace, paddr)))
+        {
+            *paddr = imgtop;
+            return PM_RET_OK;
+        }
+
+        /* Calc imgtop for next iteration */
+        imgtop += size;
+
+        /* Point to next potential img */
+        *paddr = imgtop;
+
+        /* Check if another img follows this one */
+        type = (PmType_t)mem_getByte(memspace, paddr);
+    }
+    return PM_RET_NO;
+}
+
+
+PmReturn_t
+img_findInPaths(pPmObj_t pname, PmMemSpace_t *r_memspace,
+                uint8_t const **r_imgaddr)
+{
+    uint8_t i;
+    PmReturn_t retval = PM_RET_NO;
+
+    /* Search in each path in the paths */
+    for (i = 0; i < gVmGlobal.imgPaths.pathcount; i++)
+    {
+        *r_imgaddr = gVmGlobal.imgPaths.pimg[i];
+        *r_memspace = gVmGlobal.imgPaths.memspace[i];
+        retval = img_findInPath(((pPmString_t)pname)->val,
+                                ((pPmString_t)pname)->length,
+                                *r_memspace, r_imgaddr);
+        if (retval == PM_RET_NO)
+        {
+            continue;
+        }
+        else if (retval == PM_RET_OK)
+        {
+            break;
+        }
+        else
+        {
+            return retval;
+        }
+    }
+
+    return retval;
+}
+
+
+PmReturn_t
+img_appendToPath(PmMemSpace_t memspace, uint8_t const * const paddr)
+{
+    uint8_t i;
+
+    if (gVmGlobal.imgPaths.pathcount >= PM_NUM_IMG_PATHS)
+    {
+        return PM_RET_NO;
+    }
+
+    i = gVmGlobal.imgPaths.pathcount;
+
+    gVmGlobal.imgPaths.memspace[i] = memspace;
+    gVmGlobal.imgPaths.pimg[i] = paddr;
+    gVmGlobal.imgPaths.pathcount++;
+
+    return PM_RET_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/img.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,75 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __IMG_H__
+#define __IMG_H__
+
+
+/**
+ * \file
+ * \brief Image header
+ *
+ * Created to eliminate a circular include
+ * among mem, string and obj.
+ */
+
+
+/** The maximum number of paths available in PmImgPaths */
+#define PM_NUM_IMG_PATHS 4
+
+
+typedef struct PmImgPaths_s
+{
+    PmMemSpace_t memspace[PM_NUM_IMG_PATHS];
+    uint8_t const *pimg[PM_NUM_IMG_PATHS];
+    uint8_t pathcount;
+}
+PmImgPaths_t, *pPmImgPaths_t;
+
+
+/**
+ * Code image object
+ *
+ * A type to hold code images in the heap.
+ * A code image with an object descriptor at the front.
+ * Used for storing image objects during ipm;
+ * the code object keeps a reference to this object.
+ */
+typedef struct PmCodeImgObj_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Null-term? char array */
+    uint8_t val[1];
+} PmCodeImgObj_t,
+ *pPmCodeImgObj_t;
+
+
+/**
+ * Iterates over all paths in the paths array until the named module is found.
+ * Returns the memspace,address of the head of the module.
+ *
+ * @param pname Pointer to the name of the desired module
+ * @param r_memspace Return by reference the memory space of the module
+ * @param r_imgaddr Return by reference the address of the module's image
+ * @return Return status
+ */
+PmReturn_t img_findInPaths(pPmObj_t pname, PmMemSpace_t *r_memspace,
+                           uint8_t const **r_imgaddr);
+
+/**
+ * Appends the given memspace and address to the image path array
+ *
+ * @param memspace The memspace
+ * @param paddr The address
+ * @return Return status
+ */
+PmReturn_t img_appendToPath(PmMemSpace_t memspace, uint8_t const * const paddr);
+
+#endif /* __IMG_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/int.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,272 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x08
+
+
+/**
+ * \file
+ * \brief Integer Object Type
+ *
+ * Integer object type operations.
+ */
+
+#include <limits.h>
+
+#include "pm.h"
+
+
+PmReturn_t
+int_dup(pPmObj_t pint, pPmObj_t *r_pint)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Allocate new int */
+    retval = heap_getChunk(sizeof(PmInt_t), (uint8_t **)r_pint);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Copy value */
+    OBJ_SET_TYPE(*r_pint, OBJ_TYPE_INT);
+    ((pPmInt_t)*r_pint)->val = ((pPmInt_t)pint)->val;
+    return retval;
+}
+
+
+PmReturn_t
+int_new(int32_t n, pPmObj_t *r_pint)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    /* If n is 0,1,-1, return static int objects from global struct */
+    if (n == 0)
+    {
+        *r_pint = PM_ZERO;
+        return PM_RET_OK;
+    }
+    if (n == 1)
+    {
+        *r_pint = PM_ONE;
+        return PM_RET_OK;
+    }
+    if (n == -1)
+    {
+        *r_pint = PM_NEGONE;
+        return PM_RET_OK;
+    }
+
+    /* Else create and return new int obj */
+    retval = heap_getChunk(sizeof(PmInt_t), (uint8_t **)r_pint);
+    PM_RETURN_IF_ERROR(retval);
+    OBJ_SET_TYPE(*r_pint, OBJ_TYPE_INT);
+    ((pPmInt_t)*r_pint)->val = n;
+    return retval;
+}
+
+
+PmReturn_t
+int_positive(pPmObj_t pobj, pPmObj_t *r_pint)
+{
+    PmReturn_t retval;
+
+    /* Raise TypeError if obj is not an int */
+    if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Create new int obj */
+    return int_new(((pPmInt_t)pobj)->val, r_pint);
+}
+
+
+PmReturn_t
+int_negative(pPmObj_t pobj, pPmObj_t *r_pint)
+{
+    PmReturn_t retval;
+
+    /* Raise TypeError if obj is not an int */
+    if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Create new int obj */
+    return int_new(-((pPmInt_t)pobj)->val, r_pint);
+}
+
+
+PmReturn_t
+int_bitInvert(pPmObj_t pobj, pPmObj_t *r_pint)
+{
+    PmReturn_t retval;
+
+    /* Raise TypeError if obj is not an int */
+    if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Create new int obj */
+    return int_new(~((pPmInt_t)pobj)->val, r_pint);
+}
+
+
+PmReturn_t
+int_print(pPmObj_t pint)
+{
+    PmReturn_t retval = PM_RET_OK;
+    uint8_t buf[12];
+
+    C_ASSERT(pint != C_NULL);
+
+    /* Raise TypeError if obj is not an int */
+    if (OBJ_GET_TYPE(pint) != OBJ_TYPE_INT)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    retval = sli_ltoa10(((pPmInt_t)pint)->val, buf, sizeof(buf));
+    PM_RETURN_IF_ERROR(retval);
+    sli_puts(buf);
+
+    return retval;
+}
+
+
+PmReturn_t
+int_printHex(pPmObj_t pint)
+{
+    uint8_t buf[9];
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(OBJ_GET_TYPE(pint) == OBJ_TYPE_INT);
+
+    /* Print the integer object */
+    retval = sli_ltoa16(((pPmInt_t)pint)->val, buf, sizeof(buf), 1);
+    sli_puts(buf);
+    return retval;
+}
+
+
+PmReturn_t
+int_pow(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pn)
+{
+    int32_t x;
+    int32_t y;
+    int32_t n;
+    PmReturn_t retval;
+
+    /* Raise TypeError if args aren't ints */
+    if ((OBJ_GET_TYPE(px) != OBJ_TYPE_INT)
+        || (OBJ_GET_TYPE(py) != OBJ_TYPE_INT))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    x = ((pPmInt_t)px)->val;
+    y = ((pPmInt_t)py)->val;
+
+    /* Raise Value error if exponent is negative */
+    if (y < 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_VAL);
+        return retval;
+    }
+
+    /* Calculate x raised to y */
+    n = 1;
+    while (y > 0)
+    {
+        n = n * x;
+        y--;
+    }
+    retval = int_new(n, r_pn);
+
+    return retval;
+}
+
+
+PmReturn_t
+int_divmod(pPmObj_t px, pPmObj_t py, uint8_t op, pPmObj_t *r_pxopy)
+{
+    int32_t x;
+    int32_t y;
+    int32_t xdivy;
+    int32_t xmody;
+    int32_t xopy;
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Raise TypeError if args aren't ints */
+    if ((OBJ_GET_TYPE(px) != OBJ_TYPE_INT)
+        || (OBJ_GET_TYPE(py) != OBJ_TYPE_INT))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    x = ((pPmInt_t)px)->val;
+    y = ((pPmInt_t)py)->val;
+
+    /* Raise ZeroDivisionError if denominator is zero */
+    if (y == 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_ZDIV);
+        return retval;
+    }
+
+    /* Issue #167: Make overflow silent until exceptions can be caught */
+    /* (-sys.maxint-1)/-1 is the only overflow case. */
+    /* TODO:  enable the overflow for Issue #169 */
+    /*
+    if ((y == -1) && (op == '/') && (x < 0)
+        && ((uint32_t)x == (0 - (uint32_t)x)))
+    {
+        PM_RAISE(retval, PM_RET_EX_OFLOW);
+        return retval;
+    }
+    */
+
+    /* Shortcut when denominator is one or negative one */
+    if (y == 1)
+    {
+        xdivy = x;
+        xmody = 0;
+    }
+    else if (y == -1)
+    {
+        xdivy = -x;
+        xmody = 0;
+    }
+
+    else
+    {
+        xdivy = x / y;
+        xmody = x - xdivy * y;
+
+        /*
+         * If the remainder is non-0 and the signs of x and y differ,
+         * C89 doesn't define whether xdivy is now the floor or the
+         * ceiling of the infinitely precise quotient.  We want the floor,
+         * and we have it iff the remainder's sign matches y's.
+         */
+        if ((xmody != 0) && ((y ^ xmody) < 0))
+        {
+            xmody += y;
+            --xdivy;
+            C_ASSERT(xmody && ((y ^ xmody) >= 0));
+        }
+    }
+    xopy = (op == '/') ? xdivy : xmody;
+    return int_new(xopy, r_pxopy);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/int.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,129 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __INT_H__
+#define __INT_H__
+
+
+/**
+ * \file
+ * \brief Integer Object Type
+ *
+ * Integer object type header.
+ */
+
+/**
+ * Integer obj
+ *
+ * 32b signed integer
+ */
+typedef struct PmInt_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Integer value */
+    int32_t val;
+} PmInt_t,
+ *pPmInt_t;
+
+
+/**
+ * Creates a duplicate Integer object
+ *
+ * Created specifically for the index value in FOR_LOOP.
+ *
+ * @param   pint Pointer to int obj to duplicate.
+ * @param   r_pint Return by ref, ptr to new int
+ * @return  Return status
+ */
+PmReturn_t int_dup(pPmObj_t pint, pPmObj_t *r_pint);
+
+/**
+ * Creates a new Integer object
+ *
+ * @param   val Value to assign int (signed 32-bit).
+ * @param   r_pint Return by ref, ptr to new int
+ * @return  Return status
+ */
+PmReturn_t int_new(int32_t val, pPmObj_t *r_pint);
+
+/**
+ * Implements the UNARY_POSITIVE bcode.
+ *
+ * Creates a new int with the same value as the given int.
+ *
+ * @param   pobj Pointer to integer object
+ * @param   r_pint Return by reference, ptr to int
+ * @return  Return status
+ */
+PmReturn_t int_positive(pPmObj_t pobj, pPmObj_t *r_pint);
+
+/**
+ * Implements the UNARY_NEGATIVE bcode.
+ *
+ * Creates a new int with a value that is the negative of the given int.
+ *
+ * @param   pobj Pointer to target object
+ * @param   r_pint Return by ref, ptr to int
+ * @return  Return status
+ */
+PmReturn_t int_negative(pPmObj_t pobj, pPmObj_t *r_pint);
+
+/**
+ * Implements the UNARY_INVERT bcode.
+ *
+ * Creates a new int with a value that is
+ * the bitwise inversion of the given int.
+ *
+ * @param   pobj Pointer to integer to invert
+ * @param   r_pint Return by reference; new integer
+ * @return  Return status
+ */
+PmReturn_t int_bitInvert(pPmObj_t pobj, pPmObj_t *r_pint);
+
+#ifdef HAVE_PRINT
+/**
+ * Sends out an integer object in decimal notation with MSB first.
+ * The number is preceded with a "-" when necessary.
+ *
+ * @param pObj Ptr to int object
+ * @return Return status
+ */
+PmReturn_t int_print(pPmObj_t pint);
+
+/**
+ * Prints the Int object in ascii-coded hexadecimal out the platform output
+ *
+ * @param pint Pointer to Int object
+ */
+PmReturn_t int_printHex(pPmObj_t pint);
+#endif /* HAVE_PRINT */
+
+/**
+ * Returns by reference an integer that is x raised to the power of y.
+ *
+ * @param px The integer base
+ * @param py The integer exponent
+ * @param r_pn Return by reference; New integer with value of x ** y
+ * @return Return status
+ */
+PmReturn_t int_pow(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pn);
+
+/**
+ * Returns by reference the result of the selected operation.
+ *
+ * @param px The integer numerator
+ * @param py The integer denominator
+ * @param op The operator selector.  '/' selects division, all else is modulus.
+ * @param r_pn Return by reference; New integer with value of x / y or x % y.
+ * @return Return status
+ */
+PmReturn_t int_divmod(pPmObj_t px, pPmObj_t py, uint8_t op, pPmObj_t *r_pxopy);
+
+#endif /* __INT_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/interp.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,2288 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x09
+
+
+/**
+ * \file
+ * \brief VM Interpreter
+ *
+ * VM interpreter operations.
+ */
+
+
+#include "pm.h"
+
+
+PmReturn_t
+interpret(const uint8_t returnOnNoThreads)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmObj_t pobj1 = C_NULL;
+    pPmObj_t pobj2 = C_NULL;
+    pPmObj_t pobj3 = C_NULL;
+    int16_t t16 = 0;
+    int8_t t8 = 0;
+    uint8_t bc;
+    uint8_t objid, objid2;
+
+    /* Activate a thread the first time */
+    retval = interp_reschedule();
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Interpret loop */
+    for (;;)
+    {
+        if (gVmGlobal.pthread == C_NULL)
+        {
+            if (returnOnNoThreads)
+            {
+                /* User chose to return on no threads left */
+                return retval;
+            }
+
+            /*
+             * Without a frame there is nothing to execute, so reschedule
+             * (possibly activating a recently added thread).
+             */
+            retval = interp_reschedule();
+            PM_BREAK_IF_ERROR(retval);
+            continue;
+        }
+
+        /* Reschedule threads if flag is true? */
+        if (gVmGlobal.reschedule)
+        {
+            retval = interp_reschedule();
+            PM_BREAK_IF_ERROR(retval);
+        }
+
+        /* Get byte; the func post-incrs PM_IP */
+        bc = mem_getByte(PM_FP->fo_memspace, &PM_IP);
+        switch (bc)
+        {
+            case POP_TOP:
+                pobj1 = PM_POP();
+                continue;
+
+            case ROT_TWO:
+                pobj1 = TOS;
+                TOS = TOS1;
+                TOS1 = pobj1;
+                continue;
+
+            case ROT_THREE:
+                pobj1 = TOS;
+                TOS = TOS1;
+                TOS1 = TOS2;
+                TOS2 = pobj1;
+                continue;
+
+            case DUP_TOP:
+                pobj1 = TOS;
+                PM_PUSH(pobj1);
+                continue;
+
+            case ROT_FOUR:
+                pobj1 = TOS;
+                TOS = TOS1;
+                TOS1 = TOS2;
+                TOS2 = TOS3;
+                TOS3 = pobj1;
+                continue;
+
+            case NOP:
+                continue;
+
+            case UNARY_POSITIVE:
+                /* Raise TypeError if TOS is not an int */
+                if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
+#ifdef HAVE_FLOAT
+                    && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_FLT)
+#endif /* HAVE_FLOAT */
+                    )
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    break;
+                }
+
+                /* When TOS is an int, this is a no-op */
+                continue;
+
+            case UNARY_NEGATIVE:
+#ifdef HAVE_FLOAT
+                if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
+                {
+                    retval = float_negative(TOS, &pobj2);
+                }
+                else
+#endif /* HAVE_FLOAT */
+                {
+                    retval = int_negative(TOS, &pobj2);
+                }
+                PM_BREAK_IF_ERROR(retval);
+                TOS = pobj2;
+                continue;
+
+            case UNARY_NOT:
+                pobj1 = PM_POP();
+                if (obj_isFalse(pobj1))
+                {
+                    PM_PUSH(PM_TRUE);
+                }
+                else
+                {
+                    PM_PUSH(PM_FALSE);
+                }
+                continue;
+
+#ifdef HAVE_BACKTICK
+            /* #244 Add support for the backtick operation (UNARY_CONVERT) */
+            case UNARY_CONVERT:
+                retval = obj_repr(TOS, &pobj3);
+                PM_BREAK_IF_ERROR(retval);
+                TOS = pobj3;
+                continue;
+#endif /* HAVE_BACKTICK */
+
+            case UNARY_INVERT:
+                /* Raise TypeError if it's not an int */
+                if (OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    break;
+                }
+
+                /* Otherwise perform bit-wise complement */
+                retval = int_bitInvert(TOS, &pobj2);
+                PM_BREAK_IF_ERROR(retval);
+                TOS = pobj2;
+                continue;
+
+            case LIST_APPEND:
+                /* list_append will raise a TypeError if TOS1 is not a list */
+                retval = list_append(TOS1, TOS);
+                PM_SP -= 2;
+                continue;
+
+            case BINARY_POWER:
+            case INPLACE_POWER:
+
+#ifdef HAVE_FLOAT
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
+                    || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
+                {
+                    /* Calculate float power */
+                    retval = float_op(TOS1, TOS, &pobj3, 'P');
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_FLOAT */
+
+                /* Calculate integer power */
+                retval = int_pow(TOS1, TOS, &pobj3);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Set return value */
+                PM_SP--;
+                TOS = pobj3;
+                continue;
+
+            case GET_ITER:
+#ifdef HAVE_GENERATORS
+                /* Raise TypeError if TOS is an instance, but not iterable */
+                if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
+                {
+                    retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1);
+                    if (retval != PM_RET_OK)
+                    {
+                        PM_RAISE(retval, PM_RET_EX_TYPE);
+                        break;
+                    }
+                }
+                else
+#endif /* HAVE_GENERATORS */
+                {
+                    /* Convert sequence to sequence-iterator */
+                    retval = seqiter_new(TOS, &pobj1);
+                    PM_BREAK_IF_ERROR(retval);
+
+                    /* Put sequence-iterator on top of stack */
+                    TOS = pobj1;
+                }
+                continue;
+
+            case BINARY_MULTIPLY:
+            case INPLACE_MULTIPLY:
+                /* If both objs are ints, perform the op */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
+                {
+                    retval = int_new(((pPmInt_t)TOS1)->val *
+                                     ((pPmInt_t)TOS)->val, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+#ifdef HAVE_FLOAT
+                else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
+                         || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
+                {
+                    retval = float_op(TOS1, TOS, &pobj3, '*');
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_FLOAT */
+
+#ifdef HAVE_REPLICATION
+                /* If it's a list replication operation */
+                else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                         && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST))
+                {
+                    t16 = (int16_t)((pPmInt_t)TOS)->val;
+                    if (t16 < 0)
+                    {
+                        t16 = 0;
+                    }
+
+                    retval = list_replicate(TOS1, t16, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* If it's a tuple replication operation */
+                else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                         && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_TUP))
+                {
+                    t16 = (int16_t)((pPmInt_t)TOS)->val;
+                    if (t16 < 0)
+                    {
+                        t16 = 0;
+                    }
+
+                    retval = tuple_replicate(TOS1, t16, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* If it's a string replication operation */
+                else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                         && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR))
+                {
+                    t16 = (int16_t)((pPmInt_t)TOS)->val;
+                    if (t16 < 0)
+                    {
+                        t16 = 0;
+                    }
+
+                    pobj2 = TOS1;
+                    pobj2 = (pPmObj_t)&((pPmString_t)pobj2)->val;
+                    retval = string_replicate(
+                        (uint8_t const **)(uint8_t *)&pobj2, t16, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_REPLICATION */
+
+                /* Otherwise raise a TypeError */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+            case BINARY_DIVIDE:
+            case INPLACE_DIVIDE:
+            case BINARY_FLOOR_DIVIDE:
+            case INPLACE_FLOOR_DIVIDE:
+
+#ifdef HAVE_FLOAT
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
+                    || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
+                {
+                    retval = float_op(TOS1, TOS, &pobj3, '/');
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_FLOAT */
+
+                /* Otherwise perform operation */
+                retval = int_divmod(TOS1, TOS, '/', &pobj3);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                TOS = pobj3;
+                continue;
+
+            case BINARY_MODULO:
+            case INPLACE_MODULO:
+
+#ifdef HAVE_STRING_FORMAT
+                /* If it's a string, perform string format */
+                if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR)
+                {
+                    retval = string_format((pPmString_t)TOS1, TOS, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_STRING_FORMAT */
+
+#ifdef HAVE_FLOAT
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
+                    || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
+                {
+                    retval = float_op(TOS1, TOS, &pobj3, '%');
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_FLOAT */
+
+                /* Otherwise perform operation */
+                retval = int_divmod(TOS1, TOS, '%', &pobj3);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                TOS = pobj3;
+                continue;
+
+            case STORE_MAP:
+                /* #213: Add support for Python 2.6 bytecodes */
+                C_ASSERT(OBJ_GET_TYPE(TOS2) == OBJ_TYPE_DIC);
+                retval = dict_setItem(TOS2, TOS, TOS1);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP -= 2;
+                continue;
+
+            case BINARY_ADD:
+            case INPLACE_ADD:
+
+#ifdef HAVE_FLOAT
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
+                    || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
+                {
+                    retval = float_op(TOS1, TOS, &pobj3, '+');
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_FLOAT */
+
+                /* If both objs are ints, perform the op */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
+                {
+                    retval = int_new(((pPmInt_t)TOS1)->val +
+                                     ((pPmInt_t)TOS)->val, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* #242: If both objs are strings, perform concatenation */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_STR)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR))
+                {
+                    retval = string_concat((pPmString_t)TOS1,
+                                           (pPmString_t)TOS,
+                                           &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* Otherwise raise a TypeError */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+            case BINARY_SUBTRACT:
+            case INPLACE_SUBTRACT:
+
+#ifdef HAVE_FLOAT
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
+                    || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
+                {
+                    retval = float_op(TOS1, TOS, &pobj3, '-');
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_FLOAT */
+
+                /* If both objs are ints, perform the op */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
+                {
+                    retval = int_new(((pPmInt_t)TOS1)->val -
+                                     ((pPmInt_t)TOS)->val, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* Otherwise raise a TypeError */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+            case BINARY_SUBSCR:
+                /* Implements TOS = TOS1[TOS]. */
+
+                if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
+                {
+                    retval = dict_getItem(TOS1, TOS, &pobj3);
+                }
+                else
+                {
+                    /* Raise a TypeError if index is not an Integer or Bool */
+                    if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
+                        && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
+                    {
+                        PM_RAISE(retval, PM_RET_EX_TYPE);
+                        break;
+                    }
+
+                    pobj1 = TOS1;
+#ifdef HAVE_BYTEARRAY
+                    /* If object is an instance, get the thing it contains */
+                    if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
+                    {
+                        retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
+                                              PM_NONE,
+                                              &pobj2);
+                        PM_RETURN_IF_ERROR(retval);
+                        pobj1 = pobj2;
+                    }
+#endif /* HAVE_BYTEARRAY */
+
+                    /* Ensure the index doesn't overflow */
+                    C_ASSERT(((pPmInt_t)TOS)->val <= 0x0000FFFF);
+                    t16 = (int16_t)((pPmInt_t)TOS)->val;
+
+                    retval = seq_getSubscript(pobj1, t16, &pobj3);
+                }
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                TOS = pobj3;
+                continue;
+
+#ifdef HAVE_FLOAT
+            /* #213: Add support for Python 2.6 bytecodes */
+            case BINARY_TRUE_DIVIDE:
+            case INPLACE_TRUE_DIVIDE:
+
+                /* Perform division; float_op() checks for types and zero-div */
+                retval = float_op(TOS1, TOS, &pobj3, '/');
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                TOS = pobj3;
+                continue;
+#endif /* HAVE_FLOAT */
+
+            case SLICE_0:
+                /* Implements TOS = TOS[:], push a copy of the sequence */
+
+                /* Create a copy if it is a list */
+                if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_LST)
+                {
+                    retval = list_copy(TOS, &pobj2);
+                    PM_BREAK_IF_ERROR(retval);
+
+                    TOS = pobj2;
+                }
+
+                /* If TOS is an immutable sequence leave it (no op) */
+
+                /* Raise a TypeError for types that can not be sliced */
+                else if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_STR)
+                         && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_TUP))
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    break;
+                }
+                continue;
+
+            case STORE_SUBSCR:
+                /* Implements TOS1[TOS] = TOS2 */
+
+                /* If it's a list */
+                if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)
+                {
+                    /* Ensure subscr is an int or bool */
+                    if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
+                        && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
+                    {
+                        PM_RAISE(retval, PM_RET_EX_TYPE);
+                        break;
+                    }
+
+                    /* Set the list item */
+                    retval = list_setItem(TOS1,
+                                          (int16_t)(((pPmInt_t)TOS)->val),
+                                          TOS2);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP -= 3;
+                    continue;
+                }
+
+                /* If it's a dict */
+                if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
+                {
+                    /* Set the dict item */
+                    retval = dict_setItem(TOS1, TOS, TOS2);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP -= 3;
+                    continue;
+                }
+
+#ifdef HAVE_BYTEARRAY
+                /* If object is an instance, get the thing it contains */
+                if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_CLI)
+                {
+                    retval = dict_getItem((pPmObj_t)((pPmInstance_t)TOS1)->cli_attrs,
+                                          PM_NONE,
+                                          &pobj2);
+
+                    /* Raise TypeError if instance isn't a ByteArray */
+                    if ((retval == PM_RET_EX_KEY)
+                        || (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_BYA))
+                    {
+                        PM_RAISE(retval, PM_RET_EX_TYPE);
+                        break;
+                    }
+                    PM_BREAK_IF_ERROR(retval);
+
+                    /* Ensure subscr is an int or bool */
+                    if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
+                        && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
+                    {
+                        PM_RAISE(retval, PM_RET_EX_TYPE);
+                        break;
+                    }
+
+                    retval = bytearray_setItem(pobj2,
+                                               (int16_t)(((pPmInt_t)TOS)->val),
+                                               TOS2);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP -= 3;
+                    continue;
+                }
+#endif /* HAVE_BYTEARRAY */
+
+                /* TypeError for all else */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+#ifdef HAVE_DEL
+            case DELETE_SUBSCR:
+
+                if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)
+                    && (OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT))
+                {
+                    retval = list_delItem(TOS1,
+                                          (int16_t)((pPmInt_t)TOS)->val);
+                }
+
+                else if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
+                         && (OBJ_GET_TYPE(TOS) <= OBJ_TYPE_HASHABLE_MAX))
+                {
+                    retval = dict_delItem(TOS1, TOS);
+                }
+
+                /* Raise TypeError if obj is not a list or dict */
+                else
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                }
+
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP -= 2;
+                continue;
+#endif /* HAVE_DEL */
+
+            case BINARY_LSHIFT:
+            case INPLACE_LSHIFT:
+                /* If both objs are ints, perform the op */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
+                {
+                    retval = int_new(((pPmInt_t)TOS1)->val <<
+                                     ((pPmInt_t)TOS)->val, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* Otherwise raise a TypeError */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+            case BINARY_RSHIFT:
+            case INPLACE_RSHIFT:
+                /* If both objs are ints, perform the op */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
+                {
+                    retval = int_new(((pPmInt_t)TOS1)->val >>
+                                     ((pPmInt_t)TOS)->val, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* Otherwise raise a TypeError */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+            case BINARY_AND:
+            case INPLACE_AND:
+                /* If both objs are ints, perform the op */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
+                {
+                    retval = int_new(((pPmInt_t)TOS1)->val &
+                                     ((pPmInt_t)TOS)->val, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* Otherwise raise a TypeError */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+            case BINARY_XOR:
+            case INPLACE_XOR:
+                /* If both objs are ints, perform the op */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
+                {
+                    retval = int_new(((pPmInt_t)TOS1)->val ^
+                                     ((pPmInt_t)TOS)->val, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* Otherwise raise a TypeError */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+            case BINARY_OR:
+            case INPLACE_OR:
+                /* If both objs are ints, perform the op */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                    && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
+                {
+                    retval = int_new(((pPmInt_t)TOS1)->val |
+                                     ((pPmInt_t)TOS)->val, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+
+                /* Otherwise raise a TypeError */
+                PM_RAISE(retval, PM_RET_EX_TYPE);
+                break;
+
+#ifdef HAVE_PRINT
+            case PRINT_EXPR:
+                /* Print interactive expression */
+                /* Fallthrough */
+
+            case PRINT_ITEM:
+                if (gVmGlobal.needSoftSpace && (bc == PRINT_ITEM))
+                {
+                    retval = plat_putByte(' ');
+                    PM_BREAK_IF_ERROR(retval);
+                }
+                gVmGlobal.needSoftSpace = C_TRUE;
+
+                /* Print out topmost stack element */
+                retval = obj_print(TOS, (uint8_t)(bc == PRINT_EXPR), C_FALSE);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                if (bc != PRINT_EXPR)
+                {
+                    continue;
+                }
+                /* If PRINT_EXPR, Fallthrough to print a newline */
+
+            case PRINT_NEWLINE:
+                gVmGlobal.needSoftSpace = C_FALSE;
+                if (gVmGlobal.somethingPrinted)
+                {
+                    retval = plat_putByte('\n');
+                    gVmGlobal.somethingPrinted = C_FALSE;
+                }
+                PM_BREAK_IF_ERROR(retval);
+                continue;
+#endif /* HAVE_PRINT */
+
+            case BREAK_LOOP:
+            {
+                pPmBlock_t pb1 = PM_FP->fo_blockstack;
+
+                /* Ensure there's a block */
+                C_ASSERT(pb1 != C_NULL);
+
+                /* Delete blocks until first loop block */
+                while ((pb1->b_type != B_LOOP) && (pb1->next != C_NULL))
+                {
+                    pobj2 = (pPmObj_t)pb1;
+                    pb1 = pb1->next;
+                    retval = heap_freeChunk(pobj2);
+                    PM_BREAK_IF_ERROR(retval);
+                }
+
+                /* Test again outside while loop */
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Restore PM_SP */
+                PM_SP = pb1->b_sp;
+
+                /* Goto handler */
+                PM_IP = pb1->b_handler;
+
+                /* Pop and delete this block */
+                PM_FP->fo_blockstack = pb1->next;
+                retval = heap_freeChunk((pPmObj_t)pb1);
+                PM_BREAK_IF_ERROR(retval);
+            }
+                continue;
+
+            case LOAD_LOCALS:
+                /* Pushes local attrs dict of current frame */
+                /* WARNING: does not copy fo_locals to attrs */
+                PM_PUSH((pPmObj_t)PM_FP->fo_attrs);
+                continue;
+
+            case RETURN_VALUE:
+                /* Get expiring frame's TOS */
+                pobj2 = PM_POP();
+
+#if 0 /*__DEBUG__*/
+                /* #251: This safety check is disabled because it breaks ipm */
+                /* #109: Check that stack should now be empty */
+                /* If this is regular frame (not native and not a generator) */
+                if ((PM_FP != (pPmFrame_t)(&gVmGlobal.nativeframe)) &&
+                    !(PM_FP->fo_func->f_co->co_flags & CO_GENERATOR))
+                {
+                    /* An empty stack points one past end of locals */
+                    t8 = PM_FP->fo_func->f_co->co_nlocals;
+                    C_ASSERT(PM_SP == &(PM_FP->fo_locals[t8]));
+                }
+#endif /* __DEBUG__ */
+
+                /* Keep ref of expiring frame */
+                pobj1 = (pPmObj_t)PM_FP;
+                C_ASSERT(OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FRM);
+
+                /* If no previous frame, quit thread */
+                if (PM_FP->fo_back == C_NULL)
+                {
+                    gVmGlobal.pthread->interpctrl = INTERP_CTRL_EXIT;
+                    retval = PM_RET_OK;
+                    break;
+                }
+
+                /* Otherwise return to previous frame */
+                PM_FP = PM_FP->fo_back;
+
+#ifdef HAVE_GENERATORS
+                /* If returning function was a generator */
+                if (((pPmFrame_t)pobj1)->fo_func->f_co->co_flags & CO_GENERATOR)
+                {
+                    /* Raise a StopIteration exception */
+                    PM_RAISE(retval, PM_RET_EX_STOP);
+                    break;
+                }
+#endif /* HAVE_GENERATORS */
+
+#ifdef HAVE_CLASSES
+                /*
+                 * If returning function was class initializer
+                 * do not push a return object
+                 */
+                if (((pPmFrame_t)pobj1)->fo_isInit)
+                {
+                    /* Raise TypeError if __init__ did not return None */
+                    if (pobj2 != PM_NONE)
+                    {
+                        PM_RAISE(retval, PM_RET_EX_TYPE);
+                        break;
+                    }
+                }
+                else
+#endif /* HAVE_CLASSES */
+
+                /*
+                 * Push frame's return val, except if the expiring frame
+                 * was due to an import statement
+                 */
+                if (!(((pPmFrame_t)pobj1)->fo_isImport))
+                {
+                    PM_PUSH(pobj2);
+                }
+
+                /* Deallocate expired frame */
+                PM_BREAK_IF_ERROR(heap_freeChunk(pobj1));
+                continue;
+
+#ifdef HAVE_IMPORTS
+            case IMPORT_STAR:
+                /* #102: Implement the remaining IMPORT_ bytecodes */
+                /* Expect a module on the top of the stack */
+                C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD);
+
+                /* Update PM_FP's attrs with those of the module on the stack */
+                retval = dict_update((pPmObj_t)PM_FP->fo_attrs,
+                                     (pPmObj_t)((pPmFunc_t)TOS)->f_attrs,
+                                     C_TRUE);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                continue;
+#endif /* HAVE_IMPORTS */
+
+#ifdef HAVE_GENERATORS
+            case YIELD_VALUE:
+                /* #207: Add support for the yield keyword */
+                /* Get expiring frame's TOS */
+                pobj1 = PM_POP();
+
+                /* Raise TypeError if __init__ did not return None */
+                /* (Yield means this is a generator) */
+                if ((PM_FP)->fo_isInit)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    break;
+                }
+
+                /* Return to previous frame */
+                PM_FP = PM_FP->fo_back;
+
+                /* Push yield value onto caller's TOS */
+                PM_PUSH(pobj1);
+                continue;
+#endif /* HAVE_GENERATORS */
+
+            case POP_BLOCK:
+                /* Get ptr to top block */
+                pobj1 = (pPmObj_t)PM_FP->fo_blockstack;
+
+                /* If there's no block, raise SystemError */
+                C_ASSERT(pobj1 != C_NULL);
+
+                /* Pop block */
+                PM_FP->fo_blockstack = PM_FP->fo_blockstack->next;
+
+                /* Set stack to previous level, jump to code outside block */
+                PM_SP = ((pPmBlock_t)pobj1)->b_sp;
+                PM_IP = ((pPmBlock_t)pobj1)->b_handler;
+
+                PM_BREAK_IF_ERROR(heap_freeChunk(pobj1));
+                continue;
+
+#ifdef HAVE_CLASSES
+            case BUILD_CLASS:
+                /* Create and push new class */
+                retval = class_new(TOS, TOS1, TOS2, &pobj2);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP -= 2;
+                TOS = pobj2;
+                continue;
+#endif /* HAVE_CLASSES */
+
+
+            /***************************************************
+             * All bytecodes after 90 (0x5A) have a 2-byte arg
+             * that needs to be swallowed using GET_ARG().
+             **************************************************/
+
+            case STORE_NAME:
+                /* Get name index */
+                t16 = GET_ARG();
+
+                /* Get key */
+                pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Set key=val in current frame's attrs dict */
+                retval = dict_setItem((pPmObj_t)PM_FP->fo_attrs, pobj2, TOS);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                continue;
+
+#ifdef HAVE_DEL
+            case DELETE_NAME:
+                /* Get name index */
+                t16 = GET_ARG();
+
+                /* Get key */
+                pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Remove key,val pair from current frame's attrs dict */
+                retval = dict_delItem((pPmObj_t)PM_FP->fo_attrs, pobj2);
+                PM_BREAK_IF_ERROR(retval);
+                continue;
+#endif /* HAVE_DEL */
+
+            case UNPACK_SEQUENCE:
+                /* Get ptr to sequence */
+                pobj1 = PM_POP();
+
+#ifdef HAVE_BYTEARRAY
+                /* If object is an instance, get the thing it contains */
+                if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
+                {
+                    retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
+                                          PM_NONE,
+                                          &pobj2);
+                    PM_RETURN_IF_ERROR(retval);
+                    pobj1 = pobj2;
+                }
+#endif /* HAVE_BYTEARRAY */
+
+                /*
+                 * Get the length of the sequence; this will
+                 * raise TypeError if obj is not a sequence.
+                 *
+                 * #59: Unpacking to a Dict shall not be supported
+                 */
+                retval = seq_getLength(pobj1, (uint16_t *)&t16);
+                if (retval != PM_RET_OK)
+                {
+                    GET_ARG();
+                    break;
+                }
+
+                /* Raise ValueError if seq length does not match num args */
+                if (t16 != GET_ARG())
+                {
+                    PM_RAISE(retval, PM_RET_EX_VAL);
+                    break;
+                }
+
+                /* Push sequence's objs onto stack */
+                for (; --t16 >= 0;)
+                {
+                    retval = seq_getSubscript(pobj1, t16, &pobj2);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_PUSH(pobj2);
+                }
+
+                /* Test again outside the for loop */
+                PM_BREAK_IF_ERROR(retval);
+                continue;
+
+            case FOR_ITER:
+                t16 = GET_ARG();
+
+#ifdef HAVE_GENERATORS
+                /* If TOS is an instance, call next method */
+                if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
+                {
+                    /* Get the next() func */
+                    retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1);
+                    PM_BREAK_IF_ERROR(retval);
+
+                    /* Push the func and instance as an arg */
+                    pobj2 = TOS;
+                    PM_PUSH(pobj1);
+                    PM_PUSH(pobj2);
+                    t16 = 1;
+
+                    /* Ensure pobj1 is the func */
+                    goto CALL_FUNC_FOR_ITER;
+                }
+                else
+#endif /* HAVE_GENERATORS */
+                {
+                    /* Get the next item in the sequence iterator */
+                    retval = seqiter_getNext(TOS, &pobj2);
+                }
+
+                /* Catch StopIteration early: pop iterator and break loop */
+                if (retval == PM_RET_EX_STOP)
+                {
+                    PM_SP--;
+                    retval = PM_RET_OK;
+                    PM_IP += t16;
+                    continue;
+                }
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Push the next item onto the stack */
+                PM_PUSH(pobj2);
+                continue;
+
+            case STORE_ATTR:
+                /* TOS.name = TOS1 */
+                /* Get names index */
+                t16 = GET_ARG();
+
+                /* Get attrs dict from obj */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN)
+                    || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
+                {
+                    pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
+                }
+
+#ifdef HAVE_CLASSES
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
+                {
+                    pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
+                }
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
+                {
+                    pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
+                }
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
+                {
+                    pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
+                }
+#endif /* HAVE_CLASSES */
+
+                /* Other types result in an AttributeError */
+                else
+                {
+                    PM_RAISE(retval, PM_RET_EX_ATTR);
+                    break;
+                }
+
+                /* If attrs is not a dict, raise SystemError */
+                if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC)
+                {
+                    PM_RAISE(retval, PM_RET_EX_SYS);
+                    break;
+                }
+
+                /* Get name/key obj */
+                pobj3 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Set key=val in obj's dict */
+                retval = dict_setItem(pobj2, pobj3, TOS1);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP -= 2;
+                continue;
+
+#ifdef HAVE_DEL
+            case DELETE_ATTR:
+                /* del TOS.name */
+                /* Get names index */
+                t16 = GET_ARG();
+
+                /* Get attrs dict from obj */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN)
+                    || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
+                {
+                    pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
+                }
+
+#ifdef HAVE_CLASSES
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
+                {
+                    pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
+                }
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
+                {
+                    pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
+                }
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
+                {
+                    pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
+                }
+#endif /* HAVE_CLASSES */
+
+                /* Other types result in an AttributeError */
+                else
+                {
+                    PM_RAISE(retval, PM_RET_EX_ATTR);
+                    break;
+                }
+
+                /* If attrs is not a dict, raise SystemError */
+                if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC)
+                {
+                    PM_RAISE(retval, PM_RET_EX_SYS);
+                    break;
+                }
+
+                /* Get name/key obj */
+                pobj3 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Remove key,val from obj's dict */
+                retval = dict_delItem(pobj2, pobj3);
+
+                /* Raise an AttributeError if key is not found */
+                if (retval == PM_RET_EX_KEY)
+                {
+                    PM_RAISE(retval, PM_RET_EX_ATTR);
+                }
+
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                continue;
+#endif /* HAVE_DEL */
+
+            case STORE_GLOBAL:
+                /* Get name index */
+                t16 = GET_ARG();
+
+                /* Get key */
+                pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Set key=val in global dict */
+                retval = dict_setItem((pPmObj_t)PM_FP->fo_globals, pobj2, TOS);
+                PM_BREAK_IF_ERROR(retval);
+                PM_SP--;
+                continue;
+
+#ifdef HAVE_DEL
+            case DELETE_GLOBAL:
+                /* Get name index */
+                t16 = GET_ARG();
+
+                /* Get key */
+                pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Remove key,val from globals */
+                retval = dict_delItem((pPmObj_t)PM_FP->fo_globals, pobj2);
+                PM_BREAK_IF_ERROR(retval);
+                continue;
+#endif /* HAVE_DEL */
+
+            case DUP_TOPX:
+                t16 = GET_ARG();
+                C_ASSERT(t16 <= 3);
+
+                pobj1 = TOS;
+                pobj2 = TOS1;
+                pobj3 = TOS2;
+                if (t16 >= 3)
+                    PM_PUSH(pobj3);
+                if (t16 >= 2)
+                    PM_PUSH(pobj2);
+                if (t16 >= 1)
+                    PM_PUSH(pobj1);
+                continue;
+
+            case LOAD_CONST:
+                /* Get const's index in CO */
+                t16 = GET_ARG();
+
+                /* Push const on stack */
+                PM_PUSH(PM_FP->fo_func->f_co->co_consts->val[t16]);
+                continue;
+
+            case LOAD_NAME:
+                /* Get name index */
+                t16 = GET_ARG();
+
+                /* Get name from names tuple */
+                pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Get value from frame's attrs dict */
+                retval = dict_getItem((pPmObj_t)PM_FP->fo_attrs, pobj1, &pobj2);
+                if (retval == PM_RET_EX_KEY)
+                {
+                    /* Get val from globals */
+                    retval = dict_getItem((pPmObj_t)PM_FP->fo_globals,
+                                          pobj1, &pobj2);
+
+                    /* Check for name in the builtins module if it is loaded */
+                    if ((retval == PM_RET_EX_KEY) && (PM_PBUILTINS != C_NULL))
+                    {
+                        /* Get val from builtins */
+                        retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2);
+                        if (retval == PM_RET_EX_KEY)
+                        {
+                            /* Name not defined, raise NameError */
+                            PM_RAISE(retval, PM_RET_EX_NAME);
+                            break;
+                        }
+                    }
+                }
+                PM_BREAK_IF_ERROR(retval);
+                PM_PUSH(pobj2);
+                continue;
+
+            case BUILD_TUPLE:
+                /* Get num items */
+                t16 = GET_ARG();
+                retval = tuple_new(t16, &pobj1);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Fill tuple with ptrs to objs */
+                for (; --t16 >= 0;)
+                {
+                    ((pPmTuple_t)pobj1)->val[t16] = PM_POP();
+                }
+                PM_PUSH(pobj1);
+                continue;
+
+            case BUILD_LIST:
+                t16 = GET_ARG();
+                retval = list_new(&pobj1);
+                PM_BREAK_IF_ERROR(retval);
+                for (; --t16 >= 0;)
+                {
+                    /* Insert obj into list */
+                    heap_gcPushTempRoot(pobj1, &objid);
+                    retval = list_insert(pobj1, 0, TOS);
+                    heap_gcPopTempRoot(objid);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                }
+                /* Test again outside for loop */
+                PM_BREAK_IF_ERROR(retval);
+
+                /* push list onto stack */
+                PM_PUSH(pobj1);
+                continue;
+
+            case BUILD_MAP:
+                /* Argument is ignored */
+                t16 = GET_ARG();
+                retval = dict_new(&pobj1);
+                PM_BREAK_IF_ERROR(retval);
+                PM_PUSH(pobj1);
+                continue;
+
+            case LOAD_ATTR:
+                /* Implements TOS.attr */
+                t16 = GET_ARG();
+
+#ifdef HAVE_AUTOBOX
+                /* Autobox the object, if necessary */
+                retval = class_autobox(&TOS);
+                PM_BREAK_IF_ERROR(retval);
+#endif
+
+                /* Get attrs dict from obj */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN) ||
+                    (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
+                {
+                    pobj1 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
+                }
+
+#ifdef HAVE_CLASSES
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
+                {
+                    pobj1 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
+                }
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
+                {
+                    pobj1 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
+                }
+                else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
+                {
+                    pobj1 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
+                }
+#endif /* HAVE_CLASSES */
+
+                /* Other types result in an AttributeError */
+                else
+                {
+                    PM_RAISE(retval, PM_RET_EX_ATTR);
+                    break;
+                }
+
+                /* If attrs is not a dict, raise SystemError */
+                if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_DIC)
+                {
+                    PM_RAISE(retval, PM_RET_EX_SYS);
+                    break;
+                }
+
+                /* Get name */
+                pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Get attr with given name */
+                retval = dict_getItem(pobj1, pobj2, &pobj3);
+
+#ifdef HAVE_CLASSES
+                /*
+                 * If attr is not found and object is a class or instance,
+                 * try to get the attribute from the class attrs or parent(s)
+                 */
+                if ((retval == PM_RET_EX_KEY) &&
+                    ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
+                        || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)))
+                {
+                    retval = class_getAttr(TOS, pobj2, &pobj3);
+                }
+#endif /* HAVE_CLASSES */
+
+                /* Raise an AttributeError if key is not found */
+                if (retval == PM_RET_EX_KEY)
+                {
+                    PM_RAISE(retval, PM_RET_EX_ATTR);
+                }
+                PM_BREAK_IF_ERROR(retval);
+
+#ifdef HAVE_CLASSES
+                /* If obj is an instance and attr is a func, create method */
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) &&
+                    (OBJ_GET_TYPE(pobj3) == OBJ_TYPE_FXN))
+                {
+                    pobj2 = pobj3;
+                    retval = class_method(TOS, pobj2, &pobj3);
+                    PM_BREAK_IF_ERROR(retval);
+                }
+#endif /* HAVE_CLASSES */
+
+                /* Put attr on the stack */
+                TOS = pobj3;
+                continue;
+
+            case COMPARE_OP:
+                retval = PM_RET_OK;
+                t16 = GET_ARG();
+
+#ifdef HAVE_FLOAT
+                if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
+                    || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
+                {
+                    retval = float_compare(TOS1, TOS, &pobj3, (PmCompare_t)t16);
+                    PM_SP--;
+                    TOS = pobj3;
+                    continue;
+                }
+#endif /* HAVE_FLOAT */
+
+                /* Handle all integer-to-integer (or bool) comparisons */
+                if (((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
+                     || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_BOOL))
+                    && ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)
+                        || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_BOOL)))
+                {
+                    int32_t a = ((pPmInt_t)TOS1)->val;
+                    int32_t b = ((pPmInt_t)TOS)->val;
+
+                    switch (t16)
+                    {
+                        /* *INDENT-OFF* */
+                        case COMP_LT: t8 = (int8_t)(a <  b); break;
+                        case COMP_LE: t8 = (int8_t)(a <= b); break;
+                        case COMP_EQ: t8 = (int8_t)(a == b); break;
+                        case COMP_NE: t8 = (int8_t)(a != b); break;
+                        case COMP_GT: t8 = (int8_t)(a >  b); break;
+                        case COMP_GE: t8 = (int8_t)(a >= b); break;
+                        case COMP_IS: t8 = (int8_t)(TOS == TOS1); break;
+                        case COMP_IS_NOT: t8 = (int8_t)(TOS != TOS1);break;
+                        case COMP_IN:
+                        case COMP_NOT_IN:
+                            PM_RAISE(retval, PM_RET_EX_TYPE);
+                            break;
+
+                        default:
+                            /* Other compares are not yet supported */
+                            PM_RAISE(retval, PM_RET_EX_SYS);
+                            break;
+                        /* *INDENT-ON* */
+                    }
+                    PM_BREAK_IF_ERROR(retval);
+                    pobj3 = (t8) ? PM_TRUE : PM_FALSE;
+                }
+
+                /* Handle non-integer comparisons */
+                else
+                {
+                    retval = PM_RET_OK;
+                    switch (t16)
+                    {
+                        case COMP_EQ:
+                        case COMP_NE:
+                            /* Handle equality for non-int types */
+                            pobj3 = PM_FALSE;
+                            t8 = obj_compare(TOS, TOS1);
+                            if (((t8 == C_SAME) && (t16 == COMP_EQ))
+                                || ((t8 == C_DIFFER) && (t16 == COMP_NE)))
+                            {
+                                pobj3 = PM_TRUE;
+                            }
+                            break;
+
+                        case COMP_IN:
+                        case COMP_NOT_IN:
+                            /* Handle membership comparisons */
+                            pobj3 = PM_FALSE;
+                            retval = obj_isIn(TOS, TOS1);
+                            if (retval == PM_RET_OK)
+                            {
+                                if (t16 == COMP_IN)
+                                {
+                                    pobj3 = PM_TRUE;
+                                }
+                            }
+                            else if (retval == PM_RET_NO)
+                            {
+                                retval = PM_RET_OK;
+                                if (t16 == COMP_NOT_IN)
+                                {
+                                    pobj3 = PM_TRUE;
+                                }
+                            }
+                            break;
+
+                        case COMP_IS:
+                            pobj3 = (TOS == TOS1) ? PM_TRUE : PM_FALSE;
+                            break;
+
+                        case COMP_IS_NOT:
+                            pobj3 = (TOS != TOS1) ? PM_TRUE : PM_FALSE;
+                            break;
+
+                        default:
+                            /* Other comparisons are not implemented */
+                            PM_RAISE(retval, PM_RET_EX_SYS);
+                            break;
+                    }
+                    PM_BREAK_IF_ERROR(retval);
+                }
+                PM_SP--;
+                TOS = pobj3;
+                continue;
+
+            case IMPORT_NAME:
+                /* Get name index */
+                t16 = GET_ARG();
+
+                /* Get name String obj */
+                pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Pop unused None object */
+                PM_SP--;
+
+                /* Ensure "level" is -1; no support for relative import yet */
+                C_ASSERT(obj_compare(TOS, PM_NEGONE) == C_SAME);
+
+                /* #178: Fix import so modules are reused */
+                /* Return the module if found in the modules dict (cache) */
+                retval = dict_getItem(PM_PBUILTINS, PM_MD_STR, &pobj3);
+                PM_BREAK_IF_ERROR(retval);
+                retval = dict_getItem(pobj3, pobj1, &pobj2);
+                if (retval == PM_RET_OK)
+                {
+                    TOS = pobj2;
+                    continue;
+                }
+                if (retval != PM_RET_EX_KEY)
+                {
+                    break;
+                }
+
+                /* Load module from image */
+                retval = mod_import(pobj1, &pobj2);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* #178: Fix import so modules are reused */
+                /*
+                 * Store the module's attrs/globals under the module's name
+                 * in the global module dict (cache)
+                 */
+                heap_gcPushTempRoot(pobj2, &objid);
+                retval = dict_setItem(pobj3, pobj1, pobj2);
+                heap_gcPopTempRoot(objid);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Put Module on top of stack */
+                TOS = pobj2;
+
+                /* Code after here is a duplicate of CALL_FUNCTION */
+                /* Make frame object to interpret the module's root code */
+                heap_gcPushTempRoot(pobj2, &objid);
+                retval = frame_new(pobj2, &pobj3);
+                heap_gcPopTempRoot(objid);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* No arguments to pass */
+
+                /* Keep ref to current frame */
+                ((pPmFrame_t)pobj3)->fo_back = PM_FP;
+
+                /* Handle to have None popped on return */
+                ((pPmFrame_t)pobj3)->fo_isImport = (uint8_t)1;
+
+                /* Set new frame */
+                PM_FP = (pPmFrame_t)pobj3;
+                continue;
+
+#ifdef HAVE_IMPORTS
+            case IMPORT_FROM:
+                /* #102: Implement the remaining IMPORT_ bytecodes */
+                /* Expect the module on the top of the stack */
+                C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD);
+                pobj1 = TOS;
+
+                /* Get the name of the object to import */
+                t16 = GET_ARG();
+                pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Get the object from the module's attributes */
+                retval = dict_getItem((pPmObj_t)((pPmFunc_t)pobj1)->f_attrs,
+                                      pobj2, &pobj3);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Push the object onto the top of the stack */
+                PM_PUSH(pobj3);
+                continue;
+#endif /* HAVE_IMPORTS */
+
+            case JUMP_FORWARD:
+                t16 = GET_ARG();
+                PM_IP += t16;
+                continue;
+
+            case JUMP_IF_FALSE:
+                t16 = GET_ARG();
+                if (obj_isFalse(TOS))
+                {
+                    PM_IP += t16;
+                }
+                continue;
+
+            case JUMP_IF_TRUE:
+                t16 = GET_ARG();
+                if (!obj_isFalse(TOS))
+                {
+                    PM_IP += t16;
+                }
+                continue;
+
+            case JUMP_ABSOLUTE:
+            case CONTINUE_LOOP:
+                /* Get target offset (bytes) */
+                t16 = GET_ARG();
+
+                /* Jump to base_ip + arg */
+                PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16;
+                continue;
+
+            case LOAD_GLOBAL:
+                /* Get name */
+                t16 = GET_ARG();
+                pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
+
+                /* Try globals first */
+                retval = dict_getItem((pPmObj_t)PM_FP->fo_globals,
+                                      pobj1, &pobj2);
+
+                /* If that didn't work, try builtins */
+                if (retval == PM_RET_EX_KEY)
+                {
+                    retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2);
+
+                    /* No such global, raise NameError */
+                    if (retval == PM_RET_EX_KEY)
+                    {
+                        PM_RAISE(retval, PM_RET_EX_NAME);
+                        break;
+                    }
+                }
+                PM_BREAK_IF_ERROR(retval);
+                PM_PUSH(pobj2);
+                continue;
+
+            case SETUP_LOOP:
+            {
+                uint8_t *pchunk;
+
+                /* Get block span (bytes) */
+                t16 = GET_ARG();
+
+                /* Create block */
+                retval = heap_getChunk(sizeof(PmBlock_t), &pchunk);
+                PM_BREAK_IF_ERROR(retval);
+                pobj1 = (pPmObj_t)pchunk;
+                OBJ_SET_TYPE(pobj1, OBJ_TYPE_BLK);
+
+                /* Store current stack pointer */
+                ((pPmBlock_t)pobj1)->b_sp = PM_SP;
+
+                /* Default handler is to exit block/loop */
+                ((pPmBlock_t)pobj1)->b_handler = PM_IP + t16;
+                ((pPmBlock_t)pobj1)->b_type = B_LOOP;
+
+                /* Insert block into blockstack */
+                ((pPmBlock_t)pobj1)->next = PM_FP->fo_blockstack;
+                PM_FP->fo_blockstack = (pPmBlock_t)pobj1;
+                continue;
+            }
+
+            case LOAD_FAST:
+                t16 = GET_ARG();
+                PM_PUSH(PM_FP->fo_locals[t16]);
+                continue;
+
+            case STORE_FAST:
+                t16 = GET_ARG();
+                PM_FP->fo_locals[t16] = PM_POP();
+                continue;
+
+#ifdef HAVE_DEL
+            case DELETE_FAST:
+                t16 = GET_ARG();
+                PM_FP->fo_locals[t16] = PM_NONE;
+                continue;
+#endif /* HAVE_DEL */
+
+#ifdef HAVE_ASSERT
+            case RAISE_VARARGS:
+                t16 = GET_ARG();
+
+                /* Only supports taking 1 arg for now */
+                if (t16 != 1)
+                {
+                    PM_RAISE(retval, PM_RET_EX_SYS);
+                    break;
+                }
+
+                /* Load Exception class from builtins */
+                retval = dict_getItem(PM_PBUILTINS, PM_EXCEPTION_STR, &pobj2);
+                if (retval != PM_RET_OK)
+                {
+                    PM_RAISE(retval, PM_RET_EX_SYS);
+                    break;
+                }
+
+                /* Raise TypeError if TOS is not an instance of Exception */
+                pobj1 = TOS;
+                if ((OBJ_GET_TYPE(pobj1) != OBJ_TYPE_CLO)
+                    || !class_isSubclass(pobj1, pobj2))
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    break;
+                }
+
+                /* Push the traceback, parameter and exception object */
+                TOS = PM_NONE;
+                PM_PUSH(PM_NONE);
+                PM_PUSH(pobj1);
+
+                /* Get the exception's code attr */
+                retval = dict_getItem((pPmObj_t)((pPmClass_t)pobj1)->cl_attrs,
+                                      PM_CODE_STR, &pobj2);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Raise exception by breaking with retval set to code */
+                PM_RAISE(retval, (PmReturn_t)(((pPmInt_t)pobj2)->val & 0xFF));
+                break;
+#endif /* HAVE_ASSERT */
+
+            case CALL_FUNCTION:
+                /* Get num args */
+                t16 = GET_ARG();
+
+                /* Ensure no keyword args */
+                if ((t16 & (uint16_t)0xFF00) != 0)
+                {
+                    PM_RAISE(retval, PM_RET_EX_SYS);
+                    break;
+                }
+
+                /* Get the callable */
+                pobj1 = STACK(t16);
+
+                /* Useless push to get temp-roots stack level used in cleanup */
+                heap_gcPushTempRoot(pobj1, &objid);
+
+                C_DEBUG_PRINT(VERBOSITY_LOW,
+                    "interpret(), CALL_FUNCTION on <obj type=%d @ %p>\n",
+                    OBJ_GET_TYPE(pobj1), pobj1);
+
+#ifdef HAVE_GENERATORS
+                /* If the callable is a generator function (can't be native) */
+                if ((OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FXN)
+                    && (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB)
+                    && (((pPmFunc_t)pobj1)->f_co->co_flags & CO_GENERATOR))
+                {
+#ifdef HAVE_DEFAULTARGS
+                    /* Num required args := argcount - num default args */
+                    t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount;
+                    if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
+                    {
+                        t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)->
+                            length;
+                    }
+
+                    /*
+                     * Raise a TypeError if num args passed
+                     * is more than allowed or less than required
+                     */
+                    if (((t16 & ((uint8_t)0xFF))
+                         > ((pPmFunc_t)pobj1)->f_co->co_argcount)
+                        || ((t16 & ((uint8_t)0xFF)) < t8))
+#else
+                    if ((t16 & ((uint8_t)0xFF)) !=
+                        ((pPmFunc_t)pobj1)->f_co->co_argcount)
+#endif /* HAVE_DEFAULTARGS */
+                    {
+                        PM_RAISE(retval, PM_RET_EX_TYPE);
+                        break;
+                    }
+
+                    /* Collect the function and arguments into a tuple */
+                    retval = tuple_new(t16 + 1, &pobj2);
+                    heap_gcPushTempRoot(pobj2, &objid2);
+                    PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
+                    sli_memcpy((uint8_t *)&((pPmTuple_t)pobj2)->val,
+                               (uint8_t *)&STACK(t16),
+                               (t16 + 1) * sizeof(pPmObj_t));
+
+                    /* Remove old args, push func/args tuple as one arg */
+                    PM_SP -= t16;
+                    PM_PUSH(pobj2);
+                    t16 = 1;
+
+                    /* Set pobj1 and stack to create an instance of Generator */
+                    retval = dict_getItem(PM_PBUILTINS, PM_GENERATOR_STR,
+                                          &pobj1);
+                    C_ASSERT(retval == PM_RET_OK);
+                    STACK(t16) = pobj1;
+                }
+#endif /* HAVE_GENERATORS */
+
+#ifdef HAVE_CLASSES
+                /* If the callable is a class, create an instance of it */
+                if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLO)
+                {
+                    /* This marks that the original callable was a class */
+                    bc = 0;
+
+                    /* Replace class with new instance */
+                    retval = class_instantiate(pobj1, &pobj2);
+                    heap_gcPushTempRoot(pobj2, &objid2);
+                    STACK(t16) = pobj2;
+
+                    /* If __init__ does not exist */
+                    pobj3 = C_NULL;
+                    retval = class_getAttr(pobj1, PM_INIT_STR, &pobj3);
+                    if (retval == PM_RET_EX_KEY)
+                    {
+                        /* Raise TypeError if there are args */
+                        if (t16 > 0)
+                        {
+                            PM_RAISE(retval, PM_RET_EX_TYPE);
+                            goto CALL_FUNC_CLEANUP;
+                        }
+
+                        /* Otherwise, continue with instance */
+                        heap_gcPopTempRoot(objid);
+                        continue;
+                    }
+                    else if (retval != PM_RET_OK)
+                    {
+                        PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
+                    }
+
+                    /* Slide the arguments up 1 slot in the stack */
+                    PM_SP++;
+                    for (t8 = 0; t8 < t16; t8++)
+                    {
+                        STACK(t8) = STACK(t8 + 1);
+                    }
+
+                    /* Convert __init__ to method, insert it as the callable */
+                    retval = class_method(pobj2, pobj3, &pobj1);
+                    PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
+                    heap_gcPushTempRoot(pobj2, &objid2);
+                    STACK(t16) = pobj1;
+                    /* Fall through to call the method */
+                }
+
+                if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_MTH)
+                {
+                    /* Set the method's func to be the callable */
+                    STACK(t16) = (pPmObj_t)((pPmMethod_t)pobj1)->m_func;
+
+                    /* Slide the arguments up 1 slot in the stack */
+                    PM_SP++;
+                    for (t8 = 0; t8 < t16; t8++)
+                    {
+                        STACK(t8) = STACK(t8 + 1);
+                    }
+
+                    /* Insert instance as "self" arg to the method */
+                    STACK(t16++) = (pPmObj_t)((pPmMethod_t)pobj1)->m_instance;
+
+                    /* Refresh the callable */
+                    pobj1 = (pPmObj_t)((pPmMethod_t)pobj1)->m_func;
+                }
+#endif /* HAVE_CLASSES */
+
+#ifdef HAVE_GENERATORS
+CALL_FUNC_FOR_ITER:
+#endif /* HAVE_GENERATORS */
+                /* Raise a TypeError if object is not callable */
+                if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_FXN)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    goto CALL_FUNC_CLEANUP;
+                }
+
+                /* If it is a regular func (not native) */
+                if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB)
+                {
+                    /*
+                     * #132 Raise TypeError if num args does not match the
+                     * code object's expected argcount
+                     */
+
+#ifdef HAVE_DEFAULTARGS
+                    /* Num required args := argcount - num default args */
+                    t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount;
+                    if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
+                    {
+                        t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)->
+                            length;
+                    }
+
+                    /*
+                     * Raise a TypeError if num args passed
+                     * is more than allowed or less than required
+                     */
+                    if (((t16 & ((uint8_t)0xFF))
+                         > ((pPmFunc_t)pobj1)->f_co->co_argcount)
+                        || ((t16 & ((uint8_t)0xFF)) < t8))
+#else
+                    if ((t16 & ((uint8_t)0xFF)) !=
+                        ((pPmFunc_t)pobj1)->f_co->co_argcount)
+#endif /* HAVE_DEFAULTARGS */
+                    {
+                        PM_RAISE(retval, PM_RET_EX_TYPE);
+                        break;
+                    }
+
+                    /* Make frame object to run the func object */
+                    retval = frame_new(pobj1, &pobj2);
+                    heap_gcPushTempRoot(pobj2, &objid2);
+                    PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
+
+#ifdef HAVE_CLASSES
+                    /*
+                     * If the original callable was a class, indicate that
+                     * the frame is running the initializer so that
+                     * its return object is checked for None and ignored.
+                     */
+                    if (bc == 0)
+                    {
+                        ((pPmFrame_t)pobj2)->fo_isInit = C_TRUE;
+                    }
+#endif /* HAVE_CLASSES */
+
+#ifdef HAVE_DEFAULTARGS
+                    /* If this func has default arguments, put them in place */
+                    if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
+                    {
+                        int8_t i = 0;
+
+                        /* Copy default args into the new frame's locals */
+                        for ( /* t8 set above */ ;
+                             t8 < ((pPmFunc_t)pobj1)->f_co->co_argcount; t8++)
+                        {
+                            ((pPmFrame_t)pobj2)->fo_locals[t8] =
+                                ((pPmTuple_t)((pPmFunc_t)pobj1)->
+                                 f_defaultargs)->val[i++];
+                        }
+                    }
+#endif /* HAVE_DEFAULTARGS */
+
+                    /* Pass args to new frame */
+                    while (--t16 >= 0)
+                    {
+                        /*
+                         * Pop args from stack right to left,
+                         * since args are pushed left to right,
+                         */
+                        ((pPmFrame_t)pobj2)->fo_locals[t16] = PM_POP();
+                    }
+
+#ifdef HAVE_CLOSURES
+                    /* #256: Add support for closures */
+                    /* Copy arguments that become cellvars */
+                    if (((pPmFunc_t)pobj1)->f_co->co_cellvars != C_NULL)
+                    {
+                        for (t8 = 0;
+                             t8 < ((pPmFunc_t)pobj1)->f_co->co_cellvars->length;
+                             t8++)
+                        {
+                            if (((pPmInt_t)((pPmFunc_t)pobj1)->
+                                f_co->co_cellvars->val[t8])->val >= 0)
+                            {
+                                ((pPmFrame_t)pobj2)->fo_locals[
+                                    ((pPmFunc_t)pobj1)->f_co->co_nlocals + t8] =
+                                    ((pPmFrame_t)pobj2)->fo_locals[
+                                        ((pPmInt_t)(((pPmFunc_t)pobj1)->
+                                            f_co->co_cellvars->val[t8]))->val
+                                    ];
+                            }
+                        }
+                    }
+
+                    /* Fill frame's freevars with references from closure */
+                    for (t8 = 0;
+                         t8 < ((pPmFunc_t)pobj1)->f_co->co_nfreevars;
+                         t8++)
+                    {
+                        C_ASSERT(((pPmFunc_t)pobj1)->f_closure != C_NULL);
+                        ((pPmFrame_t)pobj2)->fo_locals[
+                            ((pPmFunc_t)pobj1)->f_co->co_nlocals
+                            + ((((pPmFunc_t)pobj1)->f_co->co_cellvars == C_NULL) ? 0 : ((pPmFunc_t)pobj1)->f_co->co_cellvars->length)
+                            + t8] = ((pPmFunc_t)pobj1)->f_closure->val[t8];
+                    }
+#endif /* HAVE_CLOSURES */
+
+                    /* Pop func obj */
+                    pobj3 = PM_POP();
+
+                    /* Keep ref to current frame */
+                    ((pPmFrame_t)pobj2)->fo_back = PM_FP;
+
+                    /* Set new frame */
+                    PM_FP = (pPmFrame_t)pobj2;
+                }
+
+                /* If it's native func */
+                else if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) ==
+                         OBJ_TYPE_NOB)
+                {
+                    /* Set number of locals (arguments) */
+                    gVmGlobal.nativeframe.nf_numlocals = (uint8_t)t16;
+
+                    /* Pop args from stack */
+                    while (--t16 >= 0)
+                    {
+                        gVmGlobal.nativeframe.nf_locals[t16] = PM_POP();
+                    }
+
+                    /* Set flag, so the GC knows a native session is active */
+                    gVmGlobal.nativeframe.nf_active = C_TRUE;
+
+#ifdef HAVE_GC
+                    /* If the heap is low on memory, run the GC */
+                    if (heap_getAvail() < HEAP_GC_NF_THRESHOLD)
+                    {
+                        retval = heap_gcRun();
+                        PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
+                    }
+#endif /* HAVE_GC */
+
+                    /* Pop the function object */
+                    PM_SP--;
+
+                    /* Get native function index */
+                    pobj2 = (pPmObj_t)((pPmFunc_t)pobj1)->f_co;
+                    t16 = ((pPmNo_t)pobj2)->no_funcindx;
+
+                    /*
+                     * CALL NATIVE FXN: pass caller's frame and numargs
+                     */
+                    /* Positive index is a stdlib func */
+                    if (t16 >= 0)
+                    {
+                        retval = std_nat_fxn_table[t16] (&PM_FP);
+                    }
+
+                    /* Negative index is a usrlib func */
+                    else
+                    {
+                        retval = usr_nat_fxn_table[-t16] (&PM_FP);
+                    }
+
+                    /*
+                     * RETURN FROM NATIVE FXN
+                     */
+
+                    /* Clear flag, so frame will not be marked by the GC */
+                    gVmGlobal.nativeframe.nf_active = C_FALSE;
+
+#ifdef HAVE_CLASSES
+                    /* If class's __init__ called, do not push a return obj */
+                    if (bc == 0)
+                    {
+                        /* Raise TypeError if returned obj was not None */
+                        if ((retval == PM_RET_OK)
+                            && (gVmGlobal.nativeframe.nf_stack != PM_NONE))
+                        {
+                            PM_RAISE(retval, PM_RET_EX_TYPE);
+                            goto CALL_FUNC_CLEANUP;
+                        }
+                    }
+                    else
+#endif /* HAVE_CLASSES */
+
+                    /* If the frame pointer was switched, do nothing to TOS */
+                    if (retval == PM_RET_FRAME_SWITCH)
+                    {
+                        retval = PM_RET_OK;
+                    }
+
+                    /* Otherwise, return the result from the native function */
+                    else
+                    {
+                        PM_PUSH(gVmGlobal.nativeframe.nf_stack);
+                    }
+                }
+CALL_FUNC_CLEANUP:
+                heap_gcPopTempRoot(objid);
+                PM_BREAK_IF_ERROR(retval);
+                continue;
+
+            case MAKE_FUNCTION:
+                /* Get num default args to fxn */
+                t16 = GET_ARG();
+
+                /*
+                 * The current frame's globals become the function object's
+                 * globals.  The current frame is the container object
+                 * of this new function object
+                 */
+                retval = func_new(TOS, (pPmObj_t)PM_FP->fo_globals, &pobj2);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Put any default args in a tuple */
+                if (t16 > 0)
+                {
+
+#ifdef HAVE_DEFAULTARGS
+                    heap_gcPushTempRoot(pobj2, &objid);
+                    retval = tuple_new(t16, &pobj3);
+                    heap_gcPopTempRoot(objid);
+                    PM_BREAK_IF_ERROR(retval);
+                    PM_SP--;
+                    while (--t16 >= 0)
+                    {
+                        ((pPmTuple_t)pobj3)->val[t16] = PM_POP();
+                    }
+
+                    /* Set func's default args */
+                    ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3;
+#else
+                    /* Default arguments not configured in pmfeatures.h */
+                    PM_RAISE(retval, PM_RET_EX_SYS);
+                    break;
+#endif /* HAVE_DEFAULTARGS */
+
+                }
+                else
+                {
+                    PM_SP--;
+                }
+
+                /* Push func obj */
+                PM_PUSH(pobj2);
+                continue;
+
+#ifdef HAVE_CLOSURES
+            case MAKE_CLOSURE:
+                /* Get number of default args */
+                t16 = GET_ARG();
+                retval = func_new(TOS, (pPmObj_t)PM_FP->fo_globals, &pobj2);
+                PM_BREAK_IF_ERROR(retval);
+
+                /* Set closure of the new function */
+                ((pPmFunc_t)pobj2)->f_closure = (pPmTuple_t)TOS1;
+                PM_SP -= 2;
+
+                /* Collect any default arguments into tuple */
+                if (t16 > 0)
+                {
+                    heap_gcPushTempRoot(pobj2, &objid);
+                    retval = tuple_new(t16, &pobj3);
+                    heap_gcPopTempRoot(objid);
+                    PM_BREAK_IF_ERROR(retval);
+
+                    while (--t16 >= 0)
+                    {
+                        ((pPmTuple_t)pobj3)->val[t16] = PM_POP();
+                    }
+                    ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3;
+                }
+
+                /* Push new func with closure */
+                PM_PUSH(pobj2);
+                continue;
+
+            case LOAD_CLOSURE:
+            case LOAD_DEREF:
+                /* Loads the i'th cell of free variable storage onto TOS */
+                t16 = GET_ARG();
+                pobj1 = PM_FP->fo_locals[PM_FP->fo_func->f_co->co_nlocals + t16];
+                if (pobj1 == C_NULL)
+                {
+                    PM_RAISE(retval, PM_RET_EX_SYS);
+                    break;
+                }
+                PM_PUSH(pobj1);
+                continue;
+
+            case STORE_DEREF:
+                /* Stores TOS into the i'th cell of free variable storage */
+                t16 = GET_ARG();
+                PM_FP->fo_locals[PM_FP->fo_func->f_co->co_nlocals + t16] = PM_POP();
+                continue;
+#endif /* HAVE_CLOSURES */
+
+
+            default:
+                /* SystemError, unknown or unimplemented opcode */
+                PM_RAISE(retval, PM_RET_EX_SYS);
+                break;
+        }
+
+#ifdef HAVE_GENERATORS
+        /* If got a StopIteration exception, check for a B_LOOP block */
+        if (retval == PM_RET_EX_STOP)
+        {
+            pobj1 = (pPmObj_t)PM_FP;
+            while ((retval == PM_RET_EX_STOP) && (pobj1 != C_NULL))
+            {
+                pobj2 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_blockstack;
+                while ((retval == PM_RET_EX_STOP) && (pobj2 != C_NULL))
+                {
+                    if (((pPmBlock_t)pobj2)->b_type == B_LOOP)
+                    {
+                        /* Resume execution where the block handler says */
+                        /* Set PM_FP first, so PM_SP and PM_IP are set in the frame */
+                        PM_FP = (pPmFrame_t)pobj1;
+                        PM_SP = ((pPmBlock_t)pobj2)->b_sp;
+                        PM_IP = ((pPmBlock_t)pobj2)->b_handler;
+                        ((pPmFrame_t)pobj1)->fo_blockstack =
+                            ((pPmFrame_t)pobj1)->fo_blockstack->next;
+                        retval = PM_RET_OK;
+                        break;
+                    }
+
+                    pobj2 = (pPmObj_t)((pPmBlock_t)pobj2)->next;
+                }
+                pobj1 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_back;
+            }
+            if (retval == PM_RET_OK)
+            {
+                continue;
+            }
+        }
+#endif /* HAVE_GENERATORS */
+
+        /*
+         * If execution reaches this point, it is because
+         * a return value (from above) is not OK or we should exit the thread
+         * (return of the function). In any case, remove the
+         * current thread and reschedule.
+         */
+        PM_REPORT_IF_ERROR(retval);
+
+        /* If this is the last thread, return the error code */
+        if ((gVmGlobal.threadList->length <= 1) && (retval != PM_RET_OK))
+        {
+            break;
+        }
+
+        retval = list_remove((pPmObj_t)gVmGlobal.threadList,
+                             (pPmObj_t)gVmGlobal.pthread);
+        gVmGlobal.pthread = C_NULL;
+        PM_BREAK_IF_ERROR(retval);
+
+        retval = interp_reschedule();
+        PM_BREAK_IF_ERROR(retval);
+    }
+
+    return retval;
+}
+
+
+PmReturn_t
+interp_reschedule(void)
+{
+    PmReturn_t retval = PM_RET_OK;
+    static uint8_t threadIndex = (uint8_t)0;
+    pPmObj_t pobj;
+
+    /* If there are no threads in the runnable list, null the active thread */
+    if (gVmGlobal.threadList->length == 0)
+    {
+        gVmGlobal.pthread = C_NULL;
+    }
+
+    /* Otherwise, get the next thread in the list (round robin) */
+    else
+    {
+        if (++threadIndex >= gVmGlobal.threadList->length)
+        {
+            threadIndex = (uint8_t)0;
+        }
+        retval = list_getItem((pPmObj_t)gVmGlobal.threadList, threadIndex,
+                              &pobj);
+        gVmGlobal.pthread = (pPmThread_t)pobj;
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    /* Clear flag to indicate a reschedule has occurred */
+    interp_setRescheduleFlag(0);
+    return retval;
+}
+
+
+PmReturn_t
+interp_addThread(pPmFunc_t pfunc)
+{
+    PmReturn_t retval;
+    pPmObj_t pframe;
+    pPmObj_t pthread;
+    uint8_t objid1, objid2;
+
+    /* Create a frame for the func */
+    retval = frame_new((pPmObj_t)pfunc, &pframe);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Create a thread with this new frame */
+    heap_gcPushTempRoot(pframe, &objid1);
+    retval = thread_new(pframe, &pthread);
+    if (retval != PM_RET_OK)
+    {
+        heap_gcPopTempRoot(objid1);
+        return retval;
+    }
+
+    /* Add thread to end of list */
+    heap_gcPushTempRoot(pthread, &objid2);
+    retval = list_append((pPmObj_t)gVmGlobal.threadList, pthread);
+    heap_gcPopTempRoot(objid1);
+    return retval;
+}
+
+
+void
+interp_setRescheduleFlag(uint8_t boolean)
+{
+    gVmGlobal.reschedule = boolean;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/interp.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,316 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __INTERP_H__
+#define __INTERP_H__
+
+
+/**
+ * \file
+ * \brief VM Interpreter
+ *
+ * VM interpreter header.
+ */
+
+
+#include "thread.h"
+
+
+#define INTERP_LOOP_FOREVER          0
+#define INTERP_RETURN_ON_NO_THREADS  1
+
+
+/** Frame pointer ; currently for single thread */
+#define PM_FP (gVmGlobal.pthread->pframe)
+/** Instruction pointer */
+#define PM_IP (PM_FP->fo_ip)
+/** Argument stack pointer */
+#define PM_SP (PM_FP->fo_sp)
+
+/** top of stack */
+#define TOS             (*(PM_SP - 1))
+/** one under TOS */
+#define TOS1            (*(PM_SP - 2))
+/** two under TOS */
+#define TOS2            (*(PM_SP - 3))
+/** three under TOS */
+#define TOS3            (*(PM_SP - 4))
+/** index into stack; 0 is top, 1 is next */
+#define STACK(n)        (*(PM_SP - ((n) + 1)))
+/** pops an obj from the stack */
+#define PM_POP()        (*(--PM_SP))
+/** pushes an obj on the stack */
+#define PM_PUSH(pobj)   (*(PM_SP++) = (pobj))
+/** gets the argument (S16) from the instruction stream */
+#define GET_ARG()       mem_getWord(PM_FP->fo_memspace, &PM_IP)
+
+/** pushes an obj in the only stack slot of the native frame */
+#define NATIVE_SET_TOS(pobj) (gVmGlobal.nativeframe.nf_stack = \
+                        (pobj))
+/** gets the nth local var from the native frame locals */
+#define NATIVE_GET_LOCAL(n) (gVmGlobal.nativeframe.nf_locals[n])
+/** gets a pointer to the frame that called this native fxn */
+#define NATIVE_GET_PFRAME()   (*ppframe)
+/** gets the number of args passed to the native fxn */
+#define NATIVE_GET_NUM_ARGS() (gVmGlobal.nativeframe.nf_numlocals)
+
+
+/**
+ * COMPARE_OP enum.
+ * Used by the COMPARE_OP bytecode to determine
+ * which type of compare to perform.
+ * Must match those defined in Python.
+ */
+typedef enum PmCompare_e
+{
+    COMP_LT = 0,            /**< less than */
+    COMP_LE,                /**< less than or equal */
+    COMP_EQ,                /**< equal */
+    COMP_NE,                /**< not equal */
+    COMP_GT,                /**< greater than */
+    COMP_GE,                /**< greater than or equal */
+    COMP_IN,                /**< is in */
+    COMP_NOT_IN,            /**< is not in */
+    COMP_IS,                /**< is */
+    COMP_IS_NOT,            /**< is not */
+    COMP_EXN_MATCH          /**< do exceptions match */
+} PmCompare_t, *pPmCompare_t;
+
+/**
+ * Byte code enumeration
+ */
+typedef enum PmBcode_e
+{
+    /*
+     * Python source to create this list:
+     * import dis
+     * o = dis.opname
+     * for i in range(256):
+     *     if o[i][0] != '<':
+     *         print "\t%s," % o[i]
+     *     else:
+     *         print "\tUNUSED_%02X," % i
+     */
+    STOP_CODE = 0,              /* 0x00 */
+    POP_TOP,
+    ROT_TWO,
+    ROT_THREE,
+    DUP_TOP,
+    ROT_FOUR,
+    UNUSED_06,
+    UNUSED_07,
+    UNUSED_08,
+    NOP,
+    UNARY_POSITIVE,             /* d010 */
+    UNARY_NEGATIVE,
+    UNARY_NOT,
+    UNARY_CONVERT,
+    UNUSED_0E,
+    UNARY_INVERT,
+    UNUSED_10,                  /* 0x10 */
+    UNUSED_11,
+    LIST_APPEND,
+    BINARY_POWER,
+    BINARY_MULTIPLY,            /* d020 */
+    BINARY_DIVIDE,
+    BINARY_MODULO,
+    BINARY_ADD,
+    BINARY_SUBTRACT,
+    BINARY_SUBSCR,
+    BINARY_FLOOR_DIVIDE,
+    BINARY_TRUE_DIVIDE,
+    INPLACE_FLOOR_DIVIDE,
+    INPLACE_TRUE_DIVIDE,
+    SLICE_0,                    /* d030 */
+    SLICE_1,
+    SLICE_2,                    /* 0x20 */
+    SLICE_3,
+    UNUSED_22,
+    UNUSED_23,
+    UNUSED_24,
+    UNUSED_25,
+    UNUSED_26,
+    UNUSED_27,
+    STORE_SLICE_0,              /* d040 */
+    STORE_SLICE_1,
+    STORE_SLICE_2,
+    STORE_SLICE_3,
+    UNUSED_2C,
+    UNUSED_2D,
+    UNUSED_2E,
+    UNUSED_2F,
+    UNUSED_30,                  /* 0x30 */
+    UNUSED_31,
+    DELETE_SLICE_0,             /* d050 */
+    DELETE_SLICE_1,
+    DELETE_SLICE_2,
+    DELETE_SLICE_3,
+    STORE_MAP,
+    INPLACE_ADD,
+    INPLACE_SUBTRACT,
+    INPLACE_MULTIPLY,
+    INPLACE_DIVIDE,
+    INPLACE_MODULO,
+    STORE_SUBSCR,               /* d060 */
+    DELETE_SUBSCR,
+    BINARY_LSHIFT,
+    BINARY_RSHIFT,
+    BINARY_AND,                 /* 0x40 */
+    BINARY_XOR,
+    BINARY_OR,
+    INPLACE_POWER,
+    GET_ITER,
+    UNUSED_45,
+    PRINT_EXPR,                 /* d070 */
+    PRINT_ITEM,
+    PRINT_NEWLINE,
+    PRINT_ITEM_TO,
+    PRINT_NEWLINE_TO,
+    INPLACE_LSHIFT,
+    INPLACE_RSHIFT,
+    INPLACE_AND,
+    INPLACE_XOR,
+    INPLACE_OR,
+    BREAK_LOOP,                 /* 0x50 *//* d080 */
+    WITH_CLEANUP,
+    LOAD_LOCALS,
+    RETURN_VALUE,
+    IMPORT_STAR,
+    EXEC_STMT,
+    YIELD_VALUE,
+    POP_BLOCK,
+    END_FINALLY,
+    BUILD_CLASS,
+
+    /* Opcodes from here have an argument */
+    HAVE_ARGUMENT = 90,         /* d090 */
+    STORE_NAME = 90,
+    DELETE_NAME,
+    UNPACK_SEQUENCE,
+    FOR_ITER,
+    UNUSED_5E,
+    STORE_ATTR,
+    DELETE_ATTR,                /* 0x60 */
+    STORE_GLOBAL,
+    DELETE_GLOBAL,
+    DUP_TOPX,
+    LOAD_CONST,                 /* d100 */
+    LOAD_NAME,
+    BUILD_TUPLE,
+    BUILD_LIST,
+    BUILD_MAP,
+    LOAD_ATTR,
+    COMPARE_OP,
+    IMPORT_NAME,
+    IMPORT_FROM,
+    UNUSED_6D,
+    JUMP_FORWARD,               /* d110 */
+    JUMP_IF_FALSE,
+    JUMP_IF_TRUE,               /* 0x70 */
+    JUMP_ABSOLUTE,
+    UNUSED_72,
+    UNUSED_73,
+    LOAD_GLOBAL,
+    UNUSED_75,
+    UNUSED_76,
+    CONTINUE_LOOP,
+    SETUP_LOOP,                 /* d120 */
+    SETUP_EXCEPT,
+    SETUP_FINALLY,
+    UNUSED_7B,
+    LOAD_FAST,
+    STORE_FAST,
+    DELETE_FAST,
+    UNUSED_79,
+    UNUSED_80,                  /* 0x80 */
+    UNUSED_81,
+    RAISE_VARARGS,              /* d130 */
+    CALL_FUNCTION,
+    MAKE_FUNCTION,
+    BUILD_SLICE,
+    MAKE_CLOSURE,
+    LOAD_CLOSURE,
+    LOAD_DEREF,
+    STORE_DEREF,
+    UNUSED_8A,
+    UNUSED_8B,
+    CALL_FUNCTION_VAR,          /* d140 */
+    CALL_FUNCTION_KW,
+    CALL_FUNCTION_VAR_KW,
+    EXTENDED_ARG,
+
+    UNUSED_90, UNUSED_91, UNUSED_92, UNUSED_93,
+    UNUSED_94, UNUSED_95, UNUSED_96, UNUSED_97,
+    UNUSED_98, UNUSED_99, UNUSED_9A, UNUSED_9B,
+    UNUSED_9C, UNUSED_9D, UNUSED_9E, UNUSED_9F,
+    UNUSED_A0, UNUSED_A1, UNUSED_A2, UNUSED_A3,
+    UNUSED_A4, UNUSED_A5, UNUSED_A6, UNUSED_A7,
+    UNUSED_A8, UNUSED_A9, UNUSED_AA, UNUSED_AB,
+    UNUSED_AC, UNUSED_AD, UNUSED_AE, UNUSED_AF,
+    UNUSED_B0, UNUSED_B1, UNUSED_B2, UNUSED_B3,
+    UNUSED_B4, UNUSED_B5, UNUSED_B6, UNUSED_B7,
+    UNUSED_B8, UNUSED_B9, UNUSED_BA, UNUSED_BB,
+    UNUSED_BC, UNUSED_BD, UNUSED_BE, UNUSED_BF,
+    UNUSED_C0, UNUSED_C1, UNUSED_C2, UNUSED_C3,
+    UNUSED_C4, UNUSED_C5, UNUSED_C6, UNUSED_C7,
+    UNUSED_C8, UNUSED_C9, UNUSED_CA, UNUSED_CB,
+    UNUSED_CC, UNUSED_CD, UNUSED_CE, UNUSED_CF,
+    UNUSED_D0, UNUSED_D1, UNUSED_D2, UNUSED_D3,
+    UNUSED_D4, UNUSED_D5, UNUSED_D6, UNUSED_D7,
+    UNUSED_D8, UNUSED_D9, UNUSED_DA, UNUSED_DB,
+    UNUSED_DC, UNUSED_DD, UNUSED_DE, UNUSED_DF,
+    UNUSED_E0, UNUSED_E1, UNUSED_E2, UNUSED_E3,
+    UNUSED_E4, UNUSED_E5, UNUSED_E6, UNUSED_E7,
+    UNUSED_E8, UNUSED_E9, UNUSED_EA, UNUSED_EB,
+    UNUSED_EC, UNUSED_ED, UNUSED_EE, UNUSED_EF,
+    UNUSED_F0, UNUSED_F1, UNUSED_F2, UNUSED_F3,
+    UNUSED_F4, UNUSED_F5, UNUSED_F6, UNUSED_F7,
+    UNUSED_F8, UNUSED_F9, UNUSED_FA, UNUSED_FB,
+    UNUSED_FC, UNUSED_FD, UNUSED_FE, UNUSED_FF
+} PmBcode_t, *pPmBcode_t;
+
+
+/**
+ * Interprets the available threads. Does not return.
+ *
+ * @param returnOnNoThreads Loop forever if 0, exit with status if no more
+ *                          threads left.
+ * @return Return status if called with returnOnNoThreads != 0,
+ *         will not return otherwise.
+ */
+PmReturn_t interpret(const uint8_t returnOnNoThreads);
+
+/**
+ * Selects a thread to run and changes the VM internal variables to
+ * let the switch-loop execute the chosen one in the next iteration.
+ * For the moment the algorithm is primitive and will change the
+ * thread each time it is called in a round-robin fashion.
+ */
+PmReturn_t interp_reschedule(void);
+
+/**
+ * Creates a thread object and adds it to the queue of threads to be
+ * executed while interpret() is running.
+ *
+ * The given obj may be a function, module, or class.
+ * Creates a frame for the given function.
+ *
+ * @param pfunc Ptr to function to be executed as a thread.
+ * @return Return status
+ */
+PmReturn_t interp_addThread(pPmFunc_t pfunc);
+
+/**
+ * Sets the  reschedule flag.
+ *
+ * @param boolean Reschedule on next occasion if boolean is true; clear
+ *                the flag otherwise.
+ */
+void interp_setRescheduleFlag(uint8_t boolean);
+
+#endif /* __INTERP_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/list.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,417 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x0B
+
+
+/**
+ * \file
+ * \brief List Object Type
+ *
+ * List object type operations.
+ */
+
+
+#include "pm.h"
+
+
+PmReturn_t
+list_append(pPmObj_t plist, pPmObj_t pobj)
+{
+    PmReturn_t retval;
+    uint8_t objid;
+
+    C_ASSERT(plist != C_NULL);
+    C_ASSERT(pobj != C_NULL);
+
+    /* If plist is not a list, raise a TypeError exception */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Create new seglist if needed */
+    if (((pPmList_t)plist)->length == 0)
+    {
+        retval = seglist_new(&((pPmList_t)plist)->val);
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    /* Append object to list */
+    heap_gcPushTempRoot((pPmObj_t)((pPmList_t)plist)->val, &objid);
+    retval = seglist_appendItem(((pPmList_t)plist)->val, pobj);
+    heap_gcPopTempRoot(objid);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Increment list length */
+    ((pPmList_t)plist)->length++;
+
+    return retval;
+}
+
+
+PmReturn_t
+list_getItem(pPmObj_t plist, int16_t index, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval;
+
+    /* If it's not a list, raise TypeError */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Adjust the index */
+    if (index < 0)
+    {
+        index += ((pPmList_t)plist)->length;
+    }
+
+    /* Check the bounds of the index */
+    if ((index < 0) || (index >= ((pPmList_t)plist)->length))
+    {
+        PM_RAISE(retval, PM_RET_EX_INDX);
+        return retval;
+    }
+
+    /* Get item from seglist */
+    retval = seglist_getItem(((pPmList_t)plist)->val, index, r_pobj);
+    return retval;
+}
+
+
+PmReturn_t
+list_insert(pPmObj_t plist, int16_t index, pPmObj_t pobj)
+{
+    PmReturn_t retval;
+    int16_t len;
+    uint8_t objid;
+
+    C_ASSERT(plist != C_NULL);
+    C_ASSERT(pobj != C_NULL);
+
+    /* Raise a TypeError if plist is not a List */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        retval = PM_RET_EX_TYPE;
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    /* Adjust an out-of-bounds index value */
+    len = ((pPmList_t)plist)->length;
+    if (index < 0)
+    {
+        index += len;
+    }
+    if (index < 0)
+    {
+        index = 0;
+    }
+    if (index > len)
+    {
+        index = len;
+    }
+
+    /* Create new seglist if needed */
+    if (((pPmList_t)plist)->length == 0)
+    {
+        retval = seglist_new(&((pPmList_t)plist)->val);
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    /* Insert the item in the container */
+    heap_gcPushTempRoot((pPmObj_t)((pPmList_t)plist)->val, &objid);
+    retval = seglist_insertItem(((pPmList_t)plist)->val, pobj, index);
+    heap_gcPopTempRoot(objid);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Increment list length */
+    ((pPmList_t)plist)->length++;
+    return retval;
+}
+
+
+PmReturn_t
+list_new(pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmList_t plist = C_NULL;
+
+    /* Allocate a list */
+    retval = heap_getChunk(sizeof(PmList_t), (uint8_t **)r_pobj);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Set list type, empty the contents */
+    plist = (pPmList_t)*r_pobj;
+    OBJ_SET_TYPE(plist, OBJ_TYPE_LST);
+    plist->length = 0;
+    plist->val = C_NULL;
+
+    return retval;
+}
+
+
+PmReturn_t
+list_copy(pPmObj_t pobj, pPmObj_t *r_pobj)
+{
+    return list_replicate(pobj, 1, r_pobj);
+}
+
+
+PmReturn_t
+list_replicate(pPmObj_t psrclist, int16_t n, pPmObj_t *r_pnewlist)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t i = 0;
+    int16_t j = 0;
+    int16_t length = 0;
+    pPmObj_t pitem = C_NULL;
+    uint8_t objid;
+
+    C_ASSERT(psrclist != C_NULL);
+    C_ASSERT(r_pnewlist != C_NULL);
+
+    /* If first arg is not a list, raise TypeError */
+    if (OBJ_GET_TYPE(psrclist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+    length = ((pPmList_t)psrclist)->length;
+
+    /* Allocate new list */
+    retval = list_new(r_pnewlist);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Copy srclist the designated number of times */
+    for (i = n; i > 0; i--)
+    {
+        /* Iterate over the length of srclist */
+        for (j = 0; j < length; j++)
+        {
+            retval = list_getItem(psrclist, j, &pitem);
+            PM_RETURN_IF_ERROR(retval);
+            heap_gcPushTempRoot(*r_pnewlist, &objid);
+            retval = list_append(*r_pnewlist, pitem);
+            heap_gcPopTempRoot(objid);
+            PM_RETURN_IF_ERROR(retval);
+        }
+    }
+    return retval;
+}
+
+
+PmReturn_t
+list_setItem(pPmObj_t plist, int16_t index, pPmObj_t pobj)
+{
+    PmReturn_t retval;
+
+    /* If it's not a list, raise TypeError */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Adjust the index */
+    if (index < 0)
+    {
+        index += ((pPmList_t)plist)->length;
+    }
+
+    /* Check the bounds of the index */
+    if ((index < 0) || (index >= ((pPmList_t)plist)->length))
+    {
+        PM_RAISE(retval, PM_RET_EX_INDX);
+        return retval;
+    }
+
+    /* Set the item */
+    retval = seglist_setItem(((pPmList_t)plist)->val, pobj, index);
+    return retval;
+}
+
+
+PmReturn_t
+list_remove(pPmObj_t plist, pPmObj_t item)
+{
+    PmReturn_t retval = PM_RET_OK;
+    uint16_t index;
+
+    /* If it's not a list, raise TypeError */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Locate the item to remove */
+    retval = list_index(plist, item, &index);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Remove the item and decrement the list length */
+    retval = seglist_removeItem(((pPmList_t)plist)->val, index);
+    ((pPmList_t)plist)->length--;
+
+    /* Unlink seglist if there are no contents */
+    if (((pPmList_t)plist)->length == 0)
+    {
+        ((pPmList_t)plist)->val = C_NULL;
+    }
+
+    return retval;
+}
+
+
+PmReturn_t
+list_index(pPmObj_t plist, pPmObj_t pitem, uint16_t *r_index)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pSeglist_t pseglist;
+    pPmObj_t pobj;
+    uint16_t index;
+
+    /* If it's not a list, raise TypeError */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Raise a ValueError if the list is empty */
+    if (((pPmList_t)plist)->length == 0)
+    {
+        PM_RAISE(retval, PM_RET_EX_VAL);
+        return retval;
+    }
+
+    pseglist = ((pPmList_t)plist)->val;
+
+    /* Iterate over the list's contents */
+    for (index = 0; index < pseglist->sl_length; index++)
+    {
+        retval = seglist_getItem(pseglist, index, &pobj);
+        PM_RETURN_IF_ERROR(retval);
+
+        /* If the list item matches the given item, return the index */
+        if (obj_compare(pobj, pitem) == C_SAME)
+        {
+            *r_index = index;
+            return PM_RET_OK;
+        }
+    }
+
+    return PM_RET_EX_VAL;
+}
+
+
+PmReturn_t
+list_delItem(pPmObj_t plist, int16_t index)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    /* If it's not a list, raise TypeError */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Adjust the index */
+    if (index < 0)
+    {
+        index += ((pPmList_t)plist)->length;
+    }
+
+    /* Check the bounds of the index */
+    if ((index < 0) || (index >= ((pPmList_t)plist)->length))
+    {
+        PM_RAISE(retval, PM_RET_EX_INDX);
+        return retval;
+    }
+
+    /* Remove the item and decrement the list length */
+    retval = seglist_removeItem(((pPmList_t)plist)->val, index);
+    ((pPmList_t)plist)->length--;
+
+    /* Unlink seglist if there are no contents */
+    if (((pPmList_t)plist)->length == 0)
+    {
+        ((pPmList_t)plist)->val = C_NULL;
+    }
+
+    return retval;
+}
+
+
+#ifdef HAVE_PRINT
+PmReturn_t
+list_print(pPmObj_t plist)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t index;
+    pSeglist_t vals;
+    pPmObj_t pobj1;
+
+    C_ASSERT(plist != C_NULL);
+
+    /* If it's not a list, raise TypeError */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    plat_putByte('[');
+
+    vals = ((pPmList_t)plist)->val;
+
+    /* Iterate over the list's contents */
+    for (index = 0; index < ((pPmList_t)plist)->length; index++)
+    {
+        if (index != 0)
+        {
+            plat_putByte(',');
+            plat_putByte(' ');
+        }
+
+        /* Print each item */
+        retval = seglist_getItem(vals, index, &pobj1);
+        PM_RETURN_IF_ERROR(retval);
+        retval = obj_print(pobj1, C_FALSE, C_TRUE);
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    return plat_putByte(']');
+}
+#endif /* HAVE_PRINT */
+
+
+PmReturn_t
+list_clear(pPmObj_t plist)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(plist != C_NULL);
+
+    /* Raise TypeError if arg is not a dict */
+    if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Clear length and unlink seglist */
+    ((pPmList_t)plist)->length = 0;
+    ((pPmList_t)plist)->val = C_NULL;
+
+    return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/list.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,168 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __LIST_H__
+#define __LIST_H__
+
+/**
+ * \file
+ * \brief List Object Type
+ *
+ * List object type header.
+ */
+
+/**
+ * List obj
+ *
+ * Mutable ordered sequence of objects.  Contains ptr to linked list of nodes.
+ */
+typedef struct PmList_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** List length; number of objs linked */
+    uint16_t length;
+
+    /** Ptr to linked list of nodes */
+    pSeglist_t val;
+} PmList_t,
+ *pPmList_t;
+
+
+/**
+ * Allocates a new List object.
+ *
+ * If there is not enough memory to allocate the List,
+ * the return status will indicate an OutOfMemoryError
+ * that must be passed up to the interpreter.
+ * Otherwise, a ptr to the list is returned by reference
+ * and the return status is OK.
+ *
+ * @param   r_pobj Return; addr of ptr to obj
+ * @return  Return status
+ */
+PmReturn_t list_new(pPmObj_t *r_pobj);
+
+/**
+ * Gets the object in the list at the index.
+ *
+ * @param   plist Ptr to list obj
+ * @param   index Index into list
+ * @param   r_pobj Return by reference; ptr to item
+ * @return  Return status
+ */
+PmReturn_t list_getItem(pPmObj_t plist, int16_t index, pPmObj_t *r_pobj);
+
+/**
+ * Sets the item in the list at the index.
+ *
+ * @param   plist Ptr to list
+ * @param   index Index into list
+ * @param   pobj Ptr to obj to put into list
+ * @return  Return status
+ */
+PmReturn_t list_setItem(pPmObj_t plist, int16_t index, pPmObj_t pobj);
+
+/**
+ * Makes a copy of the given list.
+ *
+ * Allocate the necessary memory for root and nodes.
+ * Duplicate ptrs to objs.
+ *
+ * @param   pobj Ptr to source list
+ * @param   r_pobj Return; Addr of ptr to return obj
+ * @return  Return status
+ */
+PmReturn_t list_copy(pPmObj_t pobj, pPmObj_t *r_pobj);
+
+/**
+ * Appends the given obj to the end of the given list.
+ *
+ * Allocate the memory for the node.
+ * Do not copy obj, just reuse ptr.
+ *
+ * @param   plist Ptr to list
+ * @param   pobj Ptr to item to append
+ * @return  Return status
+ */
+PmReturn_t list_append(pPmObj_t plist, pPmObj_t pobj);
+
+/**
+ * Creates a new list with the contents of psrclist
+ * copied pint number of times.
+ * This implements the python code "[0,...] * N"
+ * where the list can be any list and N is an integer.
+ *
+ * @param   psrclist The source list to replicate
+ * @param   n The integer number of times to replicate it
+ * @param   r_pnewlist Return; new list with its contents set.
+ * @return  Return status
+ */
+PmReturn_t list_replicate(pPmObj_t psrclist, int16_t n, pPmObj_t *r_pnewlist);
+
+/**
+ * Inserts the object into the list at the desired index.
+ *
+ * @param   plist Ptr to list obj
+ * @param   pobj Ptr to obj to insert
+ * @param   index Index of where to insert obj
+ * @return  Return status
+ */
+PmReturn_t list_insert(pPmObj_t plist, int16_t index, pPmObj_t pobj);
+
+/**
+ * Removes a given object from the list.
+ *
+ * @param   plist Ptr to list obj
+ * @param   item Ptr to object to be removed
+ * @return  Return status
+ */
+PmReturn_t list_remove(pPmObj_t plist, pPmObj_t item);
+
+/**
+ * Finds the first index of the item that matches pitem.
+ * Returns an ValueError Exception if the item is not found.
+ *
+ * @param   plist Ptr to list obj
+ * @param   pitem Ptr to object to be removed
+ * @param   r_index Return by reference; ptr to index (C uint16)
+ * @return  Return status
+ */
+PmReturn_t list_index(pPmObj_t plist, pPmObj_t pitem, uint16_t *r_index);
+
+/**
+ * Removes the item at the given index.
+ * Raises a TypeError if the first argument is not a list.
+ * Raises an IndexError if the index is out of bounds.
+ *
+ * @param   plist Ptr to list obj
+ * @param   index Index of item to remove
+ * @return  Return status
+ */
+PmReturn_t list_delItem(pPmObj_t plist, int16_t index);
+
+#ifdef HAVE_PRINT
+/**
+ * Prints out a list. Uses obj_print() to print elements.
+ *
+ * @param pobj Object to print.
+ * @return Return status
+ */
+PmReturn_t list_print(pPmObj_t pobj);
+#endif /* HAVE_PRINT */
+
+/**
+ * Removes all items from the list and zeroes the length.
+ *
+ * @param plist List to clear
+ * @return Return status
+ */
+PmReturn_t list_clear(pPmObj_t plist);
+
+#endif /* __LIST_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/mem.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,147 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x0D
+
+
+/**
+ * \file
+ * \brief VM Memory
+ *
+ * VM memory operations.
+ * Implementations and stubs for getByte and memCopy functions.
+ * Functions to load object images from static memory.
+ */
+
+
+#include "pm.h"
+
+
+uint16_t
+mem_getWord(PmMemSpace_t memspace, uint8_t const **paddr)
+{
+    /* PyMite is little endian; get low byte first */
+    uint8_t blo = mem_getByte(memspace, paddr);
+    uint8_t bhi = mem_getByte(memspace, paddr);
+
+    return (uint16_t)(blo | (bhi << (int8_t)8));
+}
+
+
+uint32_t
+mem_getInt(PmMemSpace_t memspace, uint8_t const **paddr)
+{
+    /* PyMite is little endian; get low word first */
+    uint16_t wlo = mem_getWord(memspace, paddr);
+    uint32_t whi = mem_getWord(memspace, paddr);
+
+    return (uint32_t)(wlo | (whi << (int8_t)16));
+}
+
+
+#ifdef HAVE_FLOAT
+float
+mem_getFloat(PmMemSpace_t memspace, uint8_t const **paddr)
+{
+    union
+    {
+        char c[4];
+        float f;
+    }
+    v;
+
+#ifdef PM_FLOAT_BIG_ENDIAN
+    /* If the architecture is Big Endian, reverse the bytes of the float */
+    v.c[3] = mem_getByte(memspace, paddr);
+    v.c[2] = mem_getByte(memspace, paddr);
+    v.c[1] = mem_getByte(memspace, paddr);
+    v.c[0] = mem_getByte(memspace, paddr);
+
+#else
+    v.c[0] = mem_getByte(memspace, paddr);
+    v.c[1] = mem_getByte(memspace, paddr);
+    v.c[2] = mem_getByte(memspace, paddr);
+    v.c[3] = mem_getByte(memspace, paddr);
+
+#ifndef PM_FLOAT_LITTLE_ENDIAN
+#warning Neither PM_FLOAT_LITTLE_ENDIAN nor PM_FLOAT_BIG_ENDIAN is defined \
+         for this platform; defaulting to little endian.
+#endif
+#endif
+
+    return v.f;
+}
+#endif /* HAVE_FLOAT */
+
+
+void
+mem_copy(PmMemSpace_t memspace,
+         uint8_t **pdest, uint8_t const **psrc, uint16_t count)
+{
+    /* Copy memory from RAM */
+    if (memspace == MEMSPACE_RAM)
+    {
+        sli_memcpy(*pdest, *psrc, count);
+        *psrc += count;
+        *pdest += count;
+        return;
+    }
+
+    /* Copy memory from non-RAM to RAM */
+    else
+    {
+        uint8_t b;
+
+        for (; count > 0; count--)
+        {
+            b = mem_getByte(memspace, psrc);
+            **pdest = b;
+            (*pdest)++;
+        }
+        return;
+    }
+}
+
+
+uint16_t
+mem_getStringLength(PmMemSpace_t memspace, uint8_t const *const pstr)
+{
+    uint8_t const *psrc;
+
+    /* If source is in RAM, use a possibly optimized strlen */
+    if (memspace == MEMSPACE_RAM)
+    {
+        return sli_strlen((char const *)pstr);
+    }
+
+    /* Otherwise calculate string length */
+    psrc = pstr;
+    while (mem_getByte(memspace, &psrc) != (uint8_t)0);
+    return psrc - pstr - 1;
+}
+
+
+PmReturn_t
+mem_cmpn(uint8_t *cname, uint16_t cnamelen, PmMemSpace_t memspace,
+         uint8_t const **paddr)
+{
+    uint16_t i;
+    uint8_t b;
+
+    /* Iterate over all characters */
+    for (i = 0; i < cnamelen; i++)
+    {
+        b = mem_getByte(memspace, paddr);
+        if (cname[i] != b)
+        {
+            return PM_RET_NO;
+        }
+    }
+    return PM_RET_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/mem.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,131 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __MEM_H__
+#define __MEM_H__
+
+
+/**
+ * \file
+ * \brief VM Memory
+ *
+ * VM memory header.
+ */
+
+
+/**
+ * Memory Space enum.
+ *
+ * Defines the different addressable areas of the system.
+ */
+typedef enum PmMemSpace_e
+{
+    MEMSPACE_RAM = 0,
+    MEMSPACE_PROG,
+    MEMSPACE_EEPROM,
+    MEMSPACE_SEEPROM,
+    MEMSPACE_OTHER0,
+    MEMSPACE_OTHER1,
+    MEMSPACE_OTHER2,
+    MEMSPACE_OTHER3
+} PmMemSpace_t, *pPmMemSpace_t;
+
+
+/**
+ * Returns the byte at the given address in memspace.
+ *
+ * Increments the address (just like getc and read(1))
+ * to make image loading work (recursive).
+ *
+ * @param   memspace memory space/type
+ * @param   paddr ptr to address
+ * @return  byte from memory.
+ *          paddr - points to the next byte
+ */
+#define mem_getByte(memspace, paddr) plat_memGetByte((memspace), (paddr))
+
+/**
+ * Returns the 2-byte word at the given address in memspace.
+ *
+ * Word obtained in LITTLE ENDIAN order (per Python convention).
+ * afterward, addr points one byte past the word.
+ *
+ * @param   memspace memory space
+ * @param   paddr ptr to address
+ * @return  word from memory.
+ *          addr - points one byte past the word
+ */
+uint16_t mem_getWord(PmMemSpace_t memspace, uint8_t const **paddr);
+
+/**
+ * Returns the 4-byte int at the given address in memspace.
+ *
+ * Int obtained in LITTLE ENDIAN order (per Python convention).
+ * afterward, addr points one byte past the int.
+ *
+ * @param   memspace memory space
+ * @param   paddr ptr to address
+ * @return  int from memory.
+ *          addr - points one byte past the word
+ */
+uint32_t mem_getInt(PmMemSpace_t memspace, uint8_t const **paddr);
+
+#ifdef HAVE_FLOAT
+/**
+ * Returns the 4-byte float at the given address in memspace.
+ *
+ * Float obtained in LITTLE ENDIAN order (per Python convention).
+ * afterward, addr points one byte past the float.
+ *
+ * @param   memspace memory space
+ * @param   paddr ptr to address
+ * @return  float from memory.
+ *          addr - points one byte past the word
+ */
+float mem_getFloat(PmMemSpace_t memspace, uint8_t const **paddr);
+#endif /* HAVE_FLOAT */
+
+/**
+ * Copies count number of bytes from src in memspace to dest in RAM.
+ * Leaves dest and src pointing one byte past end of the data.
+ *
+ * @param   memspace memory space/type of source
+ * @param   pdest ptr to destination address
+ * @param   psrc  ptr to source address
+ * @param   count number of bytes to copy
+ * @return  nothing.
+ *          src, dest - point 1 past end of data
+ * @see     sli_memcpy
+ */
+void mem_copy(PmMemSpace_t memspace,
+              uint8_t **pdest, uint8_t const **psrc, uint16_t count);
+
+/**
+ * Returns the number of bytes in the C string pointed to by pstr.
+ * Does not modify pstr
+ *
+ * @param   memspace memory space/type of source
+ * @param   pstr  ptr to source C string
+ * @return  Number of bytes in the string.
+ */
+uint16_t mem_getStringLength(PmMemSpace_t memspace,
+                             uint8_t const *const pstr);
+
+/**
+ * Compares a byte array in RAM to a byte array in the given memory space
+ *
+ * @param cname Pointer to byte array in RAM
+ * @param cnamelen Length of byte array to compare
+ * @param memspace Memory space of other byte array
+ * @param paddr Pointer to address of other byte array
+ * @return PM_RET_OK if all bytes in both arrays match; PM_RET_NO otherwise
+ */
+PmReturn_t mem_cmpn(uint8_t *cname, uint16_t cnamelen, PmMemSpace_t memspace,
+                    uint8_t const **paddr);
+
+#endif /* __MEM_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/module.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,108 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x0E
+
+
+/**
+ * \file
+ * \brief Module Object Type
+ *
+ * Module object type operations.
+ */
+
+
+#include "pm.h"
+
+
+PmReturn_t
+mod_new(pPmObj_t pco, pPmObj_t *pmod)
+{
+    PmReturn_t retval;
+    uint8_t *pchunk;
+    pPmObj_t pobj;
+    uint8_t objid;
+
+    /* If it's not a code obj, raise TypeError */
+    if (OBJ_GET_TYPE(pco) != OBJ_TYPE_COB)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Alloc and init func obj */
+    retval = heap_getChunk(sizeof(PmFunc_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    *pmod = (pPmObj_t)pchunk;
+    OBJ_SET_TYPE(*pmod, OBJ_TYPE_MOD);
+    ((pPmFunc_t)*pmod)->f_co = (pPmCo_t)pco;
+    ((pPmFunc_t)*pmod)->f_attrs = C_NULL;
+    ((pPmFunc_t)*pmod)->f_globals = C_NULL;
+
+#ifdef HAVE_DEFAULTARGS
+    /* Clear the default args (only used by funcs) */
+    ((pPmFunc_t)*pmod)->f_defaultargs = C_NULL;
+#endif /* HAVE_DEFAULTARGS */
+
+#ifdef HAVE_CLOSURES
+    /* Clear field for closure tuple */
+    ((pPmFunc_t)*pmod)->f_closure = C_NULL;
+#endif /* HAVE_CLOSURES */
+
+    /* Alloc and init attrs dict */
+    heap_gcPushTempRoot(*pmod, &objid);
+    retval = dict_new(&pobj);
+    heap_gcPopTempRoot(objid);
+    ((pPmFunc_t)*pmod)->f_attrs = (pPmDict_t)pobj;
+
+    /* A module's globals is the same as its attrs */
+    ((pPmFunc_t)*pmod)->f_globals = (pPmDict_t)pobj;
+
+    return retval;
+}
+
+
+PmReturn_t
+mod_import(pPmObj_t pstr, pPmObj_t *pmod)
+{
+    PmMemSpace_t memspace;
+    uint8_t const *imgaddr = C_NULL;
+    pPmCo_t pco = C_NULL;
+    PmReturn_t retval = PM_RET_OK;
+    pPmObj_t pobj;
+    uint8_t objid;
+
+    /* If it's not a string obj, raise SyntaxError */
+    if (OBJ_GET_TYPE(pstr) != OBJ_TYPE_STR)
+    {
+        PM_RAISE(retval, PM_RET_EX_SYNTAX);
+        return retval;
+    }
+
+    /* Try to find the image in the paths */
+    retval = img_findInPaths(pstr, &memspace, &imgaddr);
+
+    /* If img was not found, raise ImportError */
+    if (retval == PM_RET_NO)
+    {
+        PM_RAISE(retval, PM_RET_EX_IMPRT);
+        return retval;
+    }
+
+    /* Load img into code obj */
+    retval = obj_loadFromImg(memspace, &imgaddr, &pobj);
+    PM_RETURN_IF_ERROR(retval);
+    pco = (pPmCo_t)pobj;
+
+    heap_gcPushTempRoot(pobj, &objid);
+    retval = mod_new((pPmObj_t)pco, pmod);
+    heap_gcPopTempRoot(objid);
+
+    return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/module.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,47 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __MODULE_H__
+#define __MODULE_H__
+
+
+/**
+ * \file
+ * \brief Module Object Type
+ *
+ * Module object type header.
+ */
+
+
+/**
+ * Creates a Module Obj for the given Code Obj.
+ *
+ * Use a func struct to represent the Module obj because
+ * the module's construction code must execute later,
+ * but set the type to OBJ_TYPE_MOD so that it is
+ * not otherwise callable.
+ *
+ * @param   pco Ptr to code obj
+ * @param   pmod Return by reference; ptr to new module obj
+ * @return  Return status
+ */
+PmReturn_t mod_new(pPmObj_t pco, pPmObj_t *pmod);
+
+/**
+ * Imports a module of the given name.
+ * Searches for an image with a matching name.
+ * A code obj is created for the code image.
+ * A module obj is created for the code obj.
+ *
+ * @param   pstr String obj containing name of code obj to load.
+ * @param   pmod Return by reference; ptr to imported module
+ * @return  Return status
+ */
+PmReturn_t mod_import(pPmObj_t pstr, pPmObj_t *pmod);
+
+#endif /* __MODULE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/obj.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,471 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x0F
+
+
+/**
+ * \file
+ * \brief Object Type
+ *
+ * Object type operations.
+ */
+
+
+#include "pm.h"
+
+
+PmReturn_t
+obj_loadFromImg(PmMemSpace_t memspace,
+                uint8_t const **paddr, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    PmObj_t obj;
+
+
+    /* Get the object descriptor */
+    obj.od = (PmObjDesc_t)0x0000;
+    OBJ_SET_TYPE(&obj, mem_getByte(memspace, paddr));
+
+    switch (OBJ_GET_TYPE(&obj))
+    {
+        case OBJ_TYPE_NON:
+            /* If it's the None object, return global None */
+            *r_pobj = PM_NONE;
+            break;
+
+        case OBJ_TYPE_INT:
+            /* Read an integer and create an integer object with the value */
+            retval = int_new(mem_getInt(memspace, paddr), r_pobj);
+            break;
+
+#ifdef HAVE_FLOAT
+        case OBJ_TYPE_FLT:
+            /* Read a float and create an float object with the value */
+            retval = float_new(mem_getFloat(memspace, paddr), r_pobj);
+            break;
+#endif /* HAVE_FLOAT */
+
+        case OBJ_TYPE_STR:
+            retval = string_loadFromImg(memspace, paddr, r_pobj);
+            break;
+
+        case OBJ_TYPE_TUP:
+            retval = tuple_loadFromImg(memspace, paddr, r_pobj);
+            break;
+
+        case OBJ_TYPE_NIM:
+            /* If it's a native code img, load into a code obj */
+            retval = no_loadFromImg(memspace, paddr, r_pobj);
+            break;
+
+        case OBJ_TYPE_CIM:
+            /* If it's a code img, load into a code obj */
+            retval = co_loadFromImg(memspace, paddr, r_pobj);
+            break;
+
+        default:
+            /* All other types should not be in an img obj */
+            PM_RAISE(retval, PM_RET_EX_SYS);
+            break;
+    }
+    return retval;
+}
+
+
+PmReturn_t
+obj_loadFromImgObj(pPmObj_t pimg, pPmObj_t *r_pobj)
+{
+    uint8_t const *imgaddr;
+    PmReturn_t retval;
+
+    C_ASSERT(OBJ_GET_TYPE(pimg) == OBJ_TYPE_CIO);
+    imgaddr = (uint8_t const *)&(((pPmCodeImgObj_t)pimg)->val);
+
+    retval = obj_loadFromImg(MEMSPACE_RAM, &imgaddr, r_pobj);
+    C_ASSERT(OBJ_GET_TYPE(*r_pobj) == OBJ_TYPE_COB);
+
+    /* All COs must reference the top of the code img obj
+     * so the image is marked and prevented from being reclaimed */
+    co_rSetCodeImgAddr((pPmCo_t)*r_pobj, (uint8_t const *)pimg);
+
+    return retval;
+}
+
+
+/* Returns true if the obj is false */
+int8_t
+obj_isFalse(pPmObj_t pobj)
+{
+    C_ASSERT(pobj != C_NULL);
+
+    switch (OBJ_GET_TYPE(pobj))
+    {
+        case OBJ_TYPE_NON:
+            /* None evaluates to false, so return true */
+            return C_TRUE;
+
+        case OBJ_TYPE_INT:
+            /* Only the integer zero is false */
+            return ((pPmInt_t)pobj)->val == 0;
+
+#ifdef HAVE_FLOAT
+        case OBJ_TYPE_FLT:
+            /* The floats 0.0 and -0.0 are false */
+            return (((pPmFloat_t) pobj)->val == 0.0)
+                || (((pPmFloat_t) pobj)->val == -0.0);
+#endif /* HAVE_FLOAT */
+
+        case OBJ_TYPE_STR:
+            /* An empty string is false */
+            return ((pPmString_t)pobj)->length == 0;
+
+        case OBJ_TYPE_TUP:
+            /* An empty tuple is false */
+            return ((pPmTuple_t)pobj)->length == 0;
+
+        case OBJ_TYPE_LST:
+            /* An empty list is false */
+            return ((pPmList_t)pobj)->length == 0;
+
+        case OBJ_TYPE_DIC:
+            /* An empty dict is false */
+            return ((pPmDict_t)pobj)->length == 0;
+
+        case OBJ_TYPE_BOOL:
+            /* C int zero means false */
+            return ((pPmBoolean_t) pobj)->val == 0;
+
+        default:
+            /*
+             * The following types are always not false:
+             * CodeObj, Function, Module, Class, ClassInstance.
+             */
+            return C_FALSE;
+    }
+}
+
+
+/* Returns true if the item is in the container object */
+PmReturn_t
+obj_isIn(pPmObj_t pobj, pPmObj_t pitem)
+{
+    PmReturn_t retval = PM_RET_NO;
+    pPmObj_t ptestItem;
+    int16_t i;
+    uint8_t c;
+
+    switch (OBJ_GET_TYPE(pobj))
+    {
+        case OBJ_TYPE_TUP:
+            /* Iterate over tuple to find item */
+            for (i = 0; i < ((pPmTuple_t)pobj)->length; i++)
+            {
+                PM_RETURN_IF_ERROR(tuple_getItem(pobj, i, &ptestItem));
+
+                if (obj_compare(pitem, ptestItem) == C_SAME)
+                {
+                    retval = PM_RET_OK;
+                    break;
+                }
+            }
+            break;
+
+        case OBJ_TYPE_STR:
+            /* Raise a TypeError if item is not a string */
+            if ((OBJ_GET_TYPE(pitem) != OBJ_TYPE_STR))
+            {
+                retval = PM_RET_EX_TYPE;
+                break;
+            }
+
+            /* Empty string is alway present */
+            if (((pPmString_t)pitem)->length == 0)
+            {
+                retval = PM_RET_OK;
+                break;
+            }
+
+            /* Raise a ValueError if the string is more than 1 char */
+            else if (((pPmString_t)pitem)->length != 1)
+            {
+                retval = PM_RET_EX_VAL;
+                break;
+            }
+
+            /* Iterate over string to find char */
+            c = ((pPmString_t)pitem)->val[0];
+            for (i = 0; i < ((pPmString_t)pobj)->length; i++)
+            {
+                if (c == ((pPmString_t)pobj)->val[i])
+                {
+                    retval = PM_RET_OK;
+                    break;
+                }
+            }
+            break;
+
+        case OBJ_TYPE_LST:
+            /* Iterate over list to find item */
+            for (i = 0; i < ((pPmList_t)pobj)->length; i++)
+            {
+                PM_RETURN_IF_ERROR(list_getItem(pobj, i, &ptestItem));
+
+                if (obj_compare(pitem, ptestItem) == C_SAME)
+                {
+                    retval = PM_RET_OK;
+                    break;
+                }
+            }
+            break;
+
+        case OBJ_TYPE_DIC:
+            /* Check if the item is one of the keys of the dict */
+            retval = dict_getItem(pobj, pitem, &ptestItem);
+            if (retval == PM_RET_EX_KEY)
+            {
+                retval = PM_RET_NO;
+            }
+            break;
+
+        default:
+            retval = PM_RET_EX_TYPE;
+            break;
+    }
+
+    return retval;
+}
+
+
+int8_t
+obj_compare(pPmObj_t pobj1, pPmObj_t pobj2)
+{
+#ifdef HAVE_BYTEARRAY
+    PmReturn_t retval;
+    pPmObj_t pobj;
+#endif /* HAVE_BYTEARRAY */
+
+    C_ASSERT(pobj1 != C_NULL);
+    C_ASSERT(pobj2 != C_NULL);
+
+    /* Check if pointers are same */
+    if (pobj1 == pobj2)
+    {
+        return C_SAME;
+    }
+
+    /* If types are different, objs must differ */
+    if (OBJ_GET_TYPE(pobj1) != OBJ_GET_TYPE(pobj2))
+    {
+        return C_DIFFER;
+    }
+
+#ifdef HAVE_BYTEARRAY
+    /* If object is an instance, get the thing it contains */
+    if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
+    {
+        retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
+                              PM_NONE,
+                              &pobj);
+        PM_RETURN_IF_ERROR(retval);
+        pobj1 = pobj;
+    }
+    if (OBJ_GET_TYPE(pobj2) == OBJ_TYPE_CLI)
+    {
+        retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj2)->cli_attrs,
+                              PM_NONE,
+                              &pobj);
+        PM_RETURN_IF_ERROR(retval);
+        pobj2 = pobj;
+    }
+
+    /* If types are different, objs must differ */
+    if (OBJ_GET_TYPE(pobj1) != OBJ_GET_TYPE(pobj2))
+    {
+        return C_DIFFER;
+    }
+#endif /* HAVE_BYTEARRAY */
+
+    /* Otherwise handle types individually */
+    switch (OBJ_GET_TYPE(pobj1))
+    {
+        case OBJ_TYPE_NON:
+            return C_SAME;
+
+        case OBJ_TYPE_INT:
+            return ((pPmInt_t)pobj1)->val ==
+                ((pPmInt_t)pobj2)->val ? C_SAME : C_DIFFER;
+
+#ifdef HAVE_FLOAT
+        case OBJ_TYPE_FLT:
+        {
+            pPmObj_t r_pobj;
+
+            float_compare(pobj1, pobj2, &r_pobj, COMP_EQ);
+            return (r_pobj == PM_TRUE) ? C_SAME : C_DIFFER;
+        }
+#endif /* HAVE_FLOAT */
+
+        case OBJ_TYPE_STR:
+            return string_compare((pPmString_t)pobj1, (pPmString_t)pobj2);
+
+        case OBJ_TYPE_TUP:
+        case OBJ_TYPE_LST:
+#ifdef HAVE_BYTEARRAY
+        case OBJ_TYPE_BYA:
+#endif /* HAVE_BYTEARRAY */
+            return seq_compare(pobj1, pobj2);
+
+        case OBJ_TYPE_DIC:
+            return dict_compare(pobj1, pobj2);
+
+        default:
+            break;
+    }
+
+    /* All other types would need same pointer to be true */
+    return C_DIFFER;
+}
+
+
+#ifdef HAVE_PRINT
+PmReturn_t
+obj_print(pPmObj_t pobj, uint8_t is_expr_repr, uint8_t is_nested)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(pobj != C_NULL);
+
+    /* Something gets printed unless it's None in an unnested expression */
+    if (!((OBJ_GET_TYPE(pobj) == OBJ_TYPE_NON) && is_expr_repr && !is_nested))
+    {
+        gVmGlobal.somethingPrinted = C_TRUE;
+    }
+
+    switch (OBJ_GET_TYPE(pobj))
+    {
+        case OBJ_TYPE_NON:
+            if (!is_expr_repr || is_nested)
+            {
+                sli_puts((uint8_t *)"None");
+            }
+            break;
+        case OBJ_TYPE_INT:
+            retval = int_print(pobj);
+            break;
+#ifdef HAVE_FLOAT
+        case OBJ_TYPE_FLT:
+            retval = float_print(pobj);
+            break;
+#endif /* HAVE_FLOAT */
+        case OBJ_TYPE_STR:
+            retval = string_print(pobj, (is_expr_repr || is_nested));
+            break;
+        case OBJ_TYPE_TUP:
+            retval = tuple_print(pobj);
+            break;
+        case OBJ_TYPE_LST:
+            retval = list_print(pobj);
+            break;
+        case OBJ_TYPE_DIC:
+            retval = dict_print(pobj);
+            break;
+        case OBJ_TYPE_BOOL:
+            sli_puts(
+                (((pPmBoolean_t) pobj)->val == C_TRUE)
+                ? (uint8_t *)"True"
+                : (uint8_t *)"False");
+            break;
+
+        case OBJ_TYPE_CLI:
+#ifdef HAVE_BYTEARRAY
+            {
+                pPmObj_t pobj2;
+
+                retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs,
+                                      PM_NONE,
+                                      (pPmObj_t *)&pobj2);
+                if ((retval == PM_RET_OK)
+                    && (OBJ_GET_TYPE(pobj2) == OBJ_TYPE_BYA))
+                {
+                    retval = bytearray_print(pobj2);
+                    break;
+                }
+            }
+#endif /* HAVE_BYTEARRAY */
+
+        case OBJ_TYPE_COB:
+        case OBJ_TYPE_MOD:
+        case OBJ_TYPE_CLO:
+        case OBJ_TYPE_FXN:
+        case OBJ_TYPE_CIM:
+        case OBJ_TYPE_NIM:
+        case OBJ_TYPE_NOB:
+        case OBJ_TYPE_THR:
+        case OBJ_TYPE_CIO:
+        case OBJ_TYPE_MTH:
+        case OBJ_TYPE_SQI:
+        {
+            uint8_t buf[17];
+            sli_puts((uint8_t *)"<obj type 0x");
+            sli_btoa16(OBJ_GET_TYPE(pobj), buf, sizeof(buf), C_TRUE);
+            sli_puts(buf);
+            sli_puts((uint8_t *)" @ 0x");
+            sli_ptoa16((intptr_t)pobj, buf, sizeof(buf), C_TRUE);
+            sli_puts(buf);
+            retval = plat_putByte('>');
+            break;
+        }
+
+        default:
+            /* Otherwise raise a TypeError */
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            break;
+    }
+    return retval;
+}
+#endif /* HAVE_PRINT */
+
+
+#ifdef HAVE_BACKTICK
+PmReturn_t
+obj_repr(pPmObj_t pobj, pPmObj_t *r_pstr)
+{
+    uint8_t tBuffer[32];
+    PmReturn_t retval = PM_RET_OK;
+    uint8_t const *pcstr = (uint8_t *)tBuffer;;
+
+    C_ASSERT(pobj != C_NULL);
+
+    switch (OBJ_GET_TYPE(pobj))
+    {
+        case OBJ_TYPE_INT:
+            retval = sli_ltoa10(((pPmInt_t)pobj)->val, tBuffer, sizeof(tBuffer));
+            PM_RETURN_IF_ERROR(retval);
+            retval = string_new(&pcstr, r_pstr);
+            break;
+
+#ifdef HAVE_FLOAT
+        case OBJ_TYPE_FLT:
+            /* #212: Use homebrew float formatter */
+            retval = sli_ftoa(((pPmFloat_t)pobj)->val, tBuffer, sizeof(tBuffer));
+            sli_strlen((char *)tBuffer);
+            retval = string_new(&pcstr, r_pstr);
+            break;
+#endif /* HAVE_FLOAT */
+
+        default:
+            /* Otherwise raise a TypeError */
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            break;
+    }
+
+    return retval;
+}
+#endif /* HAVE_BACKTICK */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/obj.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,332 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __OBJ_H__
+#define __OBJ_H__
+
+
+/**
+ * \file
+ * \brief Object Type
+ *
+ * Object type header.
+ */
+
+
+/** Object descriptor field constants */
+#define OD_MARK_SHIFT (uint8_t)0
+#define OD_FREE_SHIFT (uint8_t)1
+#define OD_SIZE_SHIFT (uint8_t)0
+#define OD_TYPE_SHIFT (uint8_t)11
+#define OD_MARK_MASK (uint16_t)(1 << OD_MARK_SHIFT)
+#define OD_FREE_MASK (uint16_t)(1 << OD_FREE_SHIFT)
+#define OD_SIZE_MASK (uint16_t)(0x07FC)
+#define OD_TYPE_MASK (uint16_t)(0xF800)
+
+/** Heap descriptor size mask */
+#define HD_SIZE_MASK (uint16_t)(OD_TYPE_MASK | OD_SIZE_MASK)
+#define HD_SIZE_SHIFT OD_SIZE_SHIFT
+
+/**
+ * Gets the free bit of the given object to the given value.
+ * If the object is marked free, it is not being used by the VM.
+ */
+#define OBJ_GET_FREE(pobj) \
+    ((((pPmObj_t)pobj)->od & OD_FREE_MASK) >> OD_FREE_SHIFT)
+
+/**
+ * Sets the free bit of the given object to the given value.
+ * Setting the free bit means that the object will use the heap descriptor
+ * structure instead of the object descriptor structure.
+ */
+#define OBJ_SET_FREE(pobj, free) \
+    do \
+    { \
+        ((pPmObj_t)pobj)->od = ((uint8_t)free) \
+                               ? ((pPmObj_t)pobj)->od | OD_FREE_MASK \
+                               : ((pPmObj_t)pobj)->od & ~OD_FREE_MASK;\
+    } \
+    while (0)
+
+/*
+ * #99: od_size bits are shifted because size is a scaled value
+ * True size is always a multiple of 4, so the lower two bits are ignored
+ * and two more significant bits are gained.
+ */
+/** Gets the size in bytes of the object. */
+#define PM_OBJ_GET_SIZE(pobj) (((pPmObj_t)pobj)->od & OD_SIZE_MASK)
+
+/**
+ * Gets the type of the object
+ * This MUST NOT be called on objects that are free.
+ */
+#define OBJ_GET_TYPE(pobj) \
+    ((((pPmObj_t)pobj)->od) >> OD_TYPE_SHIFT)
+
+/**
+ * Sets the type of the object
+ * This MUST NOT be called on objects that are free.
+ */
+#define OBJ_SET_TYPE(pobj, type) \
+    do \
+    { \
+        ((pPmObj_t)pobj)->od &= ~OD_TYPE_MASK; \
+        ((pPmObj_t)pobj)->od |= (((type) << OD_TYPE_SHIFT) & OD_TYPE_MASK); \
+    } \
+    while (0)
+
+
+/**
+ * Object type enum
+ *
+ * These values go in the od_type fields of the obj descriptor.
+ * Be sure these values correspond to those in the image creator
+ * tool.
+ * The hashable types are grouped together for convenience.
+ *
+ * WARNING: od_type must be at most 5 bits! (must be < 0x20)
+ */
+typedef enum PmType_e
+{
+    OBJ_TYPE_HASHABLE_MIN = 0x00,
+
+    /** None */
+    OBJ_TYPE_NON = 0x00,
+
+    /** Signed integer */
+    OBJ_TYPE_INT = 0x01,
+
+    /** Floating point 32b */
+    OBJ_TYPE_FLT = 0x02,
+
+    /** String */
+    OBJ_TYPE_STR = 0x03,
+
+    /** Tuple (immutable sequence) */
+    OBJ_TYPE_TUP = 0x04,
+
+    /** Code obj */
+    OBJ_TYPE_COB = 0x05,
+
+    /** Module obj */
+    OBJ_TYPE_MOD = 0x06,
+
+    /** Class obj */
+    OBJ_TYPE_CLO = 0x07,
+
+    /** Function obj (callable) */
+    OBJ_TYPE_FXN = 0x08,
+
+    /** Class instance */
+    OBJ_TYPE_CLI = 0x09,
+
+    /** Code image in static memory */
+    OBJ_TYPE_CIM = 0x0A,
+
+    /** Native function image */
+    OBJ_TYPE_NIM = 0x0B,
+
+    /** Native function object */
+    OBJ_TYPE_NOB = 0x0C,
+
+    /** Thread */
+    OBJ_TYPE_THR = 0x0D,
+
+    /** Boolean object */
+    OBJ_TYPE_BOOL = 0x0F,
+
+    /** Code image object */
+    OBJ_TYPE_CIO = 0x10,
+
+    /** Method object */
+    OBJ_TYPE_MTH = 0x11,
+
+    /* All types after this are not hashable */
+    OBJ_TYPE_HASHABLE_MAX = 0x11,
+
+    /** List (mutable sequence) */
+    OBJ_TYPE_LST = 0x12,
+
+    /** Dictionary (hash table) */
+    OBJ_TYPE_DIC = 0x13,
+
+#ifdef HAVE_BYTEARRAY
+    /** Bytearray (mutable) */
+    OBJ_TYPE_BYA = 0x14,
+#endif /* HAVE_BYTEARRAY */
+
+    /* All types after this are not accessible to the user */
+    OBJ_TYPE_ACCESSIBLE_MAX = 0x18,
+
+#ifdef HAVE_BYTEARRAY
+    /** Bytes (mutable container for Bytearray type) */
+    OBJ_TYPE_BYS = 0x18,
+#endif /* HAVE_BYTEARRAY */
+
+    /** Frame type */
+    OBJ_TYPE_FRM = 0x19,
+
+    /** Block type (for,while,try,etc) */
+    OBJ_TYPE_BLK = 0x1A,
+
+    /** Segment (within a seglist) */
+    OBJ_TYPE_SEG = 0x1B,
+
+    /** Seglist */
+    OBJ_TYPE_SGL = 0x1C,
+
+    /** Sequence iterator */
+    OBJ_TYPE_SQI = 0x1D,
+
+    /** Native frame (there is only one) */
+    OBJ_TYPE_NFM = 0x1E,
+} PmType_t, *pPmType_t;
+
+
+/**
+ * Object Descriptor
+ *
+ * All active PyMite "objects" must have this at the top of their struct.
+ * The following is a diagram of the object descriptor:
+ * \verbatim
+ *              MSb           LSb
+ *               7 6 5 4 3 2 1 0
+ *     pchunk-> +-+-+-+-+-+-+-+-+     S := Size of the chunk (2 LSbs dropped)
+ *              |     S     |F|M|     F := Free bit
+ *              +---------+-+-+-+     M := GC Mark bit
+ *              |    T    |  S  |     T := Object type (PyMite specific)
+ *              +---------+-----+
+ *              | object data   |
+ *              ...           ...
+ *              | end data      |
+ *              +---------------+
+ * \endverbatim
+ *
+ * The theoretical minimum size of an object descriptor is 2 bytes;
+ * however, the effective minimum size must be at least that of the minimum
+ * heap descriptor.  So on an 8-bit MCU, the minimum size is 8 bytes
+ * and on an MCU with 32-bit addresses, the size is 12 bytes.
+ */
+typedef uint16_t PmObjDesc_t, *pPmObjDesc_t;
+
+/** The abstract empty object type for PyMite. */
+typedef struct PmObj_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+} PmObj_t, *pPmObj_t;
+
+/** Boolean object */
+typedef struct PmBoolean_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Boolean value */
+    int32_t val;
+}
+PmBoolean_t, *pPmBoolean_t;
+
+
+/**
+ * Loads an object from an image in memory.
+ * Return pointer to object.
+ * Leave add pointing one byte past end of obj.
+ *
+ * The following lists the simple object types
+ * and their image structures:
+ * -None:
+ *      -type:      int8_t - OBJ_TYPE_NON
+ *
+ * -Int:
+ *      -type:      int8_t - OBJ_TYPE_INT
+ *      -value:     int32_t - signed integer value
+ *
+ * -Float:
+ *      -type:      int8_t - OBJ_TYPE_FLOAT
+ *      -value:     float32_t - 32-bit floating point value
+ *
+ * -Slice (is this allowed in img?):
+ *      -type:      int8_t - OBJ_TYPE_SLICE
+ *      -index1:    int16_t - first index.
+ *      -index2:    int16_t - second index.
+ *
+ * @param   memspace memory space/type
+ * @param   paddr ptr to ptr to obj
+ *          return by reference: paddr pts to
+ *          first byte after obj
+ * @param   r_pobj Return arg, the loaded object.
+ * @return  Return status
+ */
+PmReturn_t obj_loadFromImg(PmMemSpace_t memspace,
+                           uint8_t const **paddr, pPmObj_t *r_pobj);
+
+/**
+ * Loads a code object from a code image object
+ *
+ * @param pimg Ptr to a code image object
+ * @param r_pobj Return arg, the loaded object
+ * @return  Returns status
+ */
+PmReturn_t obj_loadFromImgObj(pPmObj_t pimg, pPmObj_t *r_pobj);
+
+/**
+ * Finds the boolean value of the given object.
+ *
+ * @param   pobj Ptr to object to test.
+ * @return  Nonzero value if object is False.
+ */
+int8_t obj_isFalse(pPmObj_t pobj);
+
+/**
+ * Returns the boolean true if the item is in the object
+ *
+ * @param   pobj Ptr to container object
+ * @param   pitem Ptr to item
+ */
+PmReturn_t obj_isIn(pPmObj_t pobj, pPmObj_t pitem);
+
+/**
+ * Compares two objects for equality.
+ *
+ * @param   pobj1 Ptr to first object.
+ * @param   pobj2 Ptr to second object.
+ * @return  C_SAME if the items are equivalent, C_DIFFER otherwise.
+ */
+int8_t obj_compare(pPmObj_t pobj1, pPmObj_t pobj2);
+
+/**
+ * Print an object, thereby using objects helpers.
+ *
+ * @param   pobj Ptr to object for printing.
+ * @param   is_expr_repr Influences the way None and strings are printed.
+ *                       If 0, None is printed, strings are printed.
+ *                       If 1, None is not printed and strings are printed
+ *                       surrounded with single quotes and unprintable
+ *                       characters are escaped.
+ * @param   is_nested    Influences the way None and strings are printed.
+ *                       If 1, None will be printed and strings will be
+ *                       surrounded with single quotes and escaped.
+ *                       This argument overrides the is_expr_repr argument.
+ * @return  Return status
+ */
+PmReturn_t obj_print(pPmObj_t pobj, uint8_t is_expr_repr, uint8_t is_nested);
+
+#ifdef HAVE_BACKTICK
+/**
+ * Returns by reference a string object that is the human-readable
+ * representation of the object. Used by the backtick operation (UNARY_CONVERT).
+ *
+ * @param pobj Ptr to object to represent
+ * @param r_pstr Return arg, the string object
+ * @return Return status
+ */
+PmReturn_t obj_repr(pPmObj_t pobj, pPmObj_t *r_pstr);
+#endif /* HAVE_BACKTICK */
+
+#endif /* __OBJ_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/plat_interface.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,69 @@
+/*
+# This file is Copyright 2010 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __PLAT_H__
+#define __PLAT_H__
+
+
+/** 
+ * \file
+ * \brief PyMite's Porting Interface 
+ */
+
+
+/**
+ * Initializes the platform as needed by the routines
+ * in the platform implementation file.
+ */
+PmReturn_t plat_init(void);
+
+/** De-initializes the platform after the VM is done running. */
+PmReturn_t plat_deinit(void);
+
+/**
+ * Returns the byte at the given address in memspace.
+ *
+ * Increments the address (just like getc and read(1))
+ * to make image loading work (recursively).
+ *
+ * PORT:    fill in getByte for each memspace in the system;
+ *          call sys_error for invalid memspaces.
+ *
+ * @param   memspace memory space/type
+ * @param   paddr ptr to address
+ * @return  byte from memory.
+ *          paddr - points to the next byte
+ */
+uint8_t plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr);
+
+/**
+ * Receives one byte from the default connection,
+ * usually UART0 on a target device or stdio on the desktop
+ */
+PmReturn_t plat_getByte(uint8_t *b);
+
+
+/**
+ * Sends one byte out on the default connection,
+ * usually UART0 on a target device or stdio on the desktop
+ */
+PmReturn_t plat_putByte(uint8_t b);
+
+
+/**
+ * Gets the number of timer ticks that have passed since system start.
+ */
+PmReturn_t plat_getMsTicks(uint32_t *r_ticks);
+
+
+/**
+ * Reports an exception or other error that caused the thread to quit
+ */
+void plat_reportError(PmReturn_t result);
+
+#endif /* __PLAT_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/pm.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,128 @@
+/*
+# This file is Copyright 2006 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x15
+
+
+/**
+ * \file
+ * \brief PyMite User API
+ *
+ * High-level functions to initialize and run PyMite
+ */
+
+
+#include "pm.h"
+
+
+/** Number of millisecond-ticks to pass before scheduler is run */
+#define PM_THREAD_TIMESLICE_MS  10
+
+
+/** Stores the timer millisecond-ticks since system start */
+volatile uint32_t pm_timerMsTicks = 0;
+
+/** Stores tick timestamp of last scheduler run */
+volatile uint32_t pm_lastRescheduleTimestamp = 0;
+
+
+PmReturn_t
+pm_init(uint8_t *heap_base, uint32_t heap_size,
+        PmMemSpace_t memspace, uint8_t const * const pusrimg)
+{
+    PmReturn_t retval;
+
+    /* Initialize the hardware platform */
+    retval = plat_init();
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Initialize the heap and the globals */
+    retval = heap_init(heap_base, heap_size);
+    PM_RETURN_IF_ERROR(retval);
+
+    retval = global_init();
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Load usr image info if given */
+    if (pusrimg != C_NULL)
+    {
+        retval = img_appendToPath(memspace, pusrimg);
+    }
+
+    return retval;
+}
+
+
+PmReturn_t
+pm_run(uint8_t const *modstr)
+{
+    PmReturn_t retval;
+    pPmObj_t pmod;
+    pPmObj_t pstring;
+    uint8_t const *pmodstr = modstr;
+    uint8_t objid1;
+    uint8_t objid2;
+
+    /* Import module from global struct */
+    retval = string_new(&pmodstr, &pstring);
+    PM_RETURN_IF_ERROR(retval);
+    heap_gcPushTempRoot(pstring, &objid1);
+    retval = mod_import(pstring, &pmod);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Load builtins into thread */
+    heap_gcPushTempRoot(pmod, &objid2);
+    retval = global_setBuiltins((pPmFunc_t)pmod);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Interpret the module's bcode */
+    retval = interp_addThread((pPmFunc_t)pmod);
+    PM_RETURN_IF_ERROR(retval);
+    heap_gcPopTempRoot(objid1);
+    retval = interpret(INTERP_RETURN_ON_NO_THREADS);
+
+    /*
+     * De-initialize the hardware platform.
+     * Ignore plat_deinit's retval so interpret's retval returns to caller.
+     */
+    plat_deinit();
+
+    return retval;
+}
+
+
+/* Warning: Can be called in interrupt context! */
+PmReturn_t
+pm_vmPeriodic(uint16_t usecsSinceLastCall)
+{
+    /*
+     * Add the full milliseconds to pm_timerMsTicks and store additional
+     * microseconds for the next run. Thus, usecsSinceLastCall must be
+     * less than 2^16-1000 so it will not overflow usecResidual.
+     */
+    static uint16_t usecResidual = 0;
+
+    C_ASSERT(usecsSinceLastCall < 64536);
+
+    usecResidual += usecsSinceLastCall;
+    while (usecResidual >= 1000)
+    {
+        usecResidual -= 1000;
+        pm_timerMsTicks++;
+    }
+
+    /* Check if enough time has passed for a scheduler run */
+    if ((pm_timerMsTicks - pm_lastRescheduleTimestamp)
+        >= PM_THREAD_TIMESLICE_MS)
+    {
+        interp_setRescheduleFlag((uint8_t)1);
+        pm_lastRescheduleTimestamp = pm_timerMsTicks;
+    }
+    return PM_RET_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/pm.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,262 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __PM_H__
+#define __PM_H__
+
+
+/**
+ * \file
+ * \brief PyMite Header
+ *
+ * Include things that are needed by nearly everything.
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_SNPRINTF_FORMAT
+#include <stdio.h>
+#endif
+#include <stdint.h>
+
+/**
+ * Value indicating the release of PyMite
+ *
+ * This value should be incremented for every public release.
+ * It helps locate a defect when used in conjunction with a fileID
+ * and line number.
+ */
+#define PM_RELEASE 8
+
+
+/** null for C code */
+#define C_NULL 0
+
+/** false for C code */
+#define C_FALSE (uint8_t)0
+
+/** true for C code */
+#define C_TRUE (uint8_t)1
+
+/** Comparison result is that items are the same */
+#define C_SAME (int8_t)0
+
+/** Comparison result is that items differ */
+#define C_DIFFER (int8_t)-1
+
+/** PORT inline for C code */
+#define INLINE __inline__
+
+
+/**
+ * Returns an exception error code and stores debug data
+ *
+ * This macro must be used as an rval statement.  That is, it must
+ * be used after an assignment such as "retval = " or a return statement
+ */
+#if __DEBUG__
+#define PM_RAISE(retexn, exn) \
+        do \
+        { \
+            retexn = (exn); \
+            gVmGlobal.errFileId = __FILE_ID__; \
+            gVmGlobal.errLineNum = (uint16_t)__LINE__; \
+        } while (0)
+#else
+#define PM_RAISE(retexn, exn) \
+        retexn = (exn)
+#endif
+
+/** if retval is not OK, break from the block */
+#define PM_BREAK_IF_ERROR(retval) if ((retval) != PM_RET_OK) break
+
+/** return an error code if it is not PM_RET_OK */
+#define PM_RETURN_IF_ERROR(retval)  if ((retval) != PM_RET_OK) return (retval)
+
+/** print an error message if argument is not PM_RET_OK */
+#define PM_REPORT_IF_ERROR(retval)   if ((retval) != PM_RET_OK) \
+                                        plat_reportError(retval)
+
+/** Jumps to a label if argument is not PM_RET_OK */
+#define PM_GOTO_IF_ERROR(retval, target) if ((retval) != PM_RET_OK) \
+                                            goto target
+
+#if __DEBUG__
+/** If the boolean expression fails, return the ASSERT error code */
+#define C_ASSERT(boolexpr) \
+    do \
+    { \
+        if (!((boolexpr))) \
+        { \
+            gVmGlobal.errFileId = __FILE_ID__; \
+            gVmGlobal.errLineNum = (uint16_t)__LINE__; \
+            return PM_RET_ASSERT_FAIL; \
+        } \
+    } \
+    while (0)
+
+#else
+/** Assert statements are removed from production code */
+#define C_ASSERT(boolexpr)
+#endif
+
+/** Use as the first argument to C_DEBUG_PRINT for low volume messages */
+#define VERBOSITY_LOW 1
+
+/** Use as the first argument to C_DEBUG_PRINT for medium volume messages */
+#define VERBOSITY_MEDIUM 2
+
+/** Use as the first argument to C_DEBUG_PRINT for high volume messages */
+#define VERBOSITY_HIGH 3
+
+#if __DEBUG__
+#include <stdio.h>
+
+/** To be used to set DEBUG_PRINT_VERBOSITY to a value so no prints occur */
+#define VERBOSITY_OFF 0
+
+/** Sets the level of verbosity to allow in debug prints */
+#define DEBUG_PRINT_VERBOSITY VERBOSITY_OFF
+
+/** Prints a debug message when the verbosity is within the set value */
+#define C_DEBUG_PRINT(v, f, ...) \
+    do \
+    { \
+        if (DEBUG_PRINT_VERBOSITY >= (v)) \
+        { \
+            printf("PM_DEBUG: " f, ## __VA_ARGS__); \
+        } \
+    } \
+    while (0)
+
+#else
+#define C_DEBUG_PRINT(...)
+#endif
+
+
+/**
+ * Return values for system functions
+ * to report status, errors, exceptions, etc.
+ * Normally, functions which use these values
+ * should propagate the same return value
+ * up the call tree to the interpreter.
+ */
+typedef enum PmReturn_e
+{
+    /* general status return values */
+    PM_RET_OK = 0,              /**< Everything is ok */
+    PM_RET_NO = 0xFF,           /**< General "no result" */
+    PM_RET_ERR = 0xFE,          /**< General failure */
+    PM_RET_STUB = 0xFD,         /**< Return val for stub fxn */
+    PM_RET_ASSERT_FAIL = 0xFC,  /**< Assertion failure */
+    PM_RET_FRAME_SWITCH = 0xFB, /**< Frame pointer was modified */
+    PM_RET_ALIGNMENT = 0xFA,    /**< Heap is not aligned */
+
+    /* return vals that indicate an exception occured */
+    PM_RET_EX = 0xE0,           /**< General exception */
+    PM_RET_EX_EXIT = 0xE1,      /**< System exit */
+    PM_RET_EX_IO = 0xE2,        /**< Input/output error */
+    PM_RET_EX_ZDIV = 0xE3,      /**< Zero division error */
+    PM_RET_EX_ASSRT = 0xE4,     /**< Assertion error */
+    PM_RET_EX_ATTR = 0xE5,      /**< Attribute error */
+    PM_RET_EX_IMPRT = 0xE6,     /**< Import error */
+    PM_RET_EX_INDX = 0xE7,      /**< Index error */
+    PM_RET_EX_KEY = 0xE8,       /**< Key error */
+    PM_RET_EX_MEM = 0xE9,       /**< Memory error */
+    PM_RET_EX_NAME = 0xEA,      /**< Name error */
+    PM_RET_EX_SYNTAX = 0xEB,    /**< Syntax error */
+    PM_RET_EX_SYS = 0xEC,       /**< System error */
+    PM_RET_EX_TYPE = 0xED,      /**< Type error */
+    PM_RET_EX_VAL = 0xEE,       /**< Value error */
+    PM_RET_EX_STOP = 0xEF,      /**< Stop iteration */
+    PM_RET_EX_WARN = 0xF0,      /**< Warning */
+    PM_RET_EX_OFLOW = 0xF1,     /**< Overflow */
+} PmReturn_t;
+
+
+extern volatile uint32_t pm_timerMsTicks;
+
+
+/* WARNING: The order of the following includes is critical */
+#include "plat.h"
+#include "pmfeatures.h"
+#include "pmEmptyPlatformDefs.h"
+#include "sli.h"
+#include "mem.h"
+#include "obj.h"
+#include "seq.h"
+#include "tuple.h"
+#include "strobj.h"
+#include "heap.h"
+#include "int.h"
+#include "seglist.h"
+#include "list.h"
+#include "dict.h"
+#include "codeobj.h"
+#include "func.h"
+#include "module.h"
+#include "frame.h"
+#include "class.h"
+#include "interp.h"
+#include "img.h"
+#include "global.h"
+#include "thread.h"
+#include "float.h"
+#include "plat_interface.h"
+#include "bytearray.h"
+
+
+/** Pointer to a native function used for lookup tables in interp.c */
+typedef PmReturn_t (* pPmNativeFxn_t)(pPmFrame_t *);
+extern pPmNativeFxn_t const std_nat_fxn_table[];
+extern pPmNativeFxn_t const usr_nat_fxn_table[];
+
+
+/**
+ * Initializes the PyMite virtual machine and indexes the user's application
+ * image.  The VM heap and globals are reset.  The argument, pusrimg, may be
+ * null for interactive sessions.
+ *
+ * @param heap_base The address where the contiguous heap begins
+ * @param heap_size The size in bytes (octets) of the given heap.
+ *             Must be a multiple of four.
+ * @param memspace      Memory space in which the user image is located
+ * @param pusrimg       Address of the user image in the memory space
+ * @return Return status
+ */
+PmReturn_t pm_init(uint8_t *heap_base, uint32_t heap_size,
+                   PmMemSpace_t memspace, uint8_t const * const pusrimg);
+
+/**
+ * Executes the named module
+ *
+ * @param modstr        Name of module to run
+ * @return Return status
+ */
+PmReturn_t pm_run(uint8_t const *modstr);
+
+/**
+ * Needs to be called periodically by the host program.
+ * For the desktop target, it is periodically called using a signal.
+ * For embedded targets, it needs to be called periodically. It should
+ * be called from a timer interrupt.
+ *
+ * @param usecsSinceLastCall Microseconds (not less than those) that passed
+ *                           since last call. This must be <64535.
+ * @return Return status
+ */
+PmReturn_t pm_vmPeriodic(uint16_t usecsSinceLastCall);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PM_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/pmEmptyPlatformDefs.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,31 @@
+/*
+# This file is Copyright 2010 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __PM_EMPTY_PLATFORM_DEFS_H__
+#define __PM_EMPTY_PLATFORM_DEFS_H__
+
+
+/**
+ * \file
+ * \brief Empty platform-specific definitions
+ *
+ * This file #defines as blank any undefined platform-specific
+ * definitions.
+ */
+
+/**
+ * Define a processor-specific specifier for use in declaring the heap.
+ * If not defined, make it empty.
+ * See <code>pmHeap</code> in heap.c for its use, which is:<br>
+ * <code>static PmHeap_t pmHeap PM_PLAT_HEAP_ATTR;</code>
+ */
+#if !defined(PM_PLAT_HEAP_ATTR) || defined(__DOXYGEN__)
+#define PM_PLAT_HEAP_ATTR
+#endif
+
+#endif /* __PM_EMPTY_PLATFORM_DEFS_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/pmFeatureDependencies.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,185 @@
+/*
+# This file is Copyright 2010 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __PM_EMPTY_PM_FEATURES_H__
+#define __PM_EMPTY_PM_FEATURES_H__
+
+
+/**
+ * \file
+ * \brief Platform feature descriptions and dependency checks
+ *
+ * This file explains the purpose of all of the HAVE_* features
+ * and provides logical checks for features that depend on other features.
+ *
+ * A platform defines the features it wants in src/platform/<plat>/pmfeatures.py
+ * A tool generates C HAVE_* definitions in pmfeatures.h from pmfeatures.py.
+ *
+ *
+ * HAVE_PRINT
+ * ----------
+ *
+ * When defined, bytecodes PRINT_ITEM and PRINT_NEWLINE are supported. Along
+ * with these, helper routines in the object type are compiled in that allow
+ * printing of the object.
+ * REQUIRES stdio.h to have snprintf()
+ *
+ *
+ * HAVE_GC
+ * -------
+ *
+ * When defined, the code to perform mark-sweep garbage collection is included
+ * in the build and automatic GC is enabled.  When undefined the allocator
+ * will distribute memory until none is left, after which a memory exception
+ * will occur.
+ *
+ *
+ * HAVE_FLOAT
+ * ----------
+ *
+ * When defined, the code to support floating point objects is included
+ * in the build.
+ * Issue #148 Create configurable float datatype
+ *
+ *
+ * HAVE_DEL
+ * --------
+ *
+ * When defined, the code to support the keyword del is included in the build.
+ * This involves the bytecodes: DELETE_SUBSCR, DELETE_NAME, DELETE_ATTR,
+ * DELETE_GLOBAL and DELETE_FAST.
+ *
+ *
+ * HAVE_IMPORTS
+ * ------------
+ *
+ * When defined, the code to support the IMPORT_FROM and IMPORT_STAR styles
+ * is included in the build.
+ *
+ *
+ * HAVE_DEFAULTARGS
+ * ----------------
+ *
+ * When defined, the code to support default arguments to functions is included
+ * in the build.
+ * Issue #157 Support default args
+ *
+ *
+ * HAVE_REPLICATION
+ * ----------------
+ *
+ * When defined, the code to support sequence (list, tuple, string) replcation
+ * is included in the build.
+ * This feature is required by the builtin function __bi.map().
+ * #160 Add support for string and tuple replication
+ *
+ *
+ * HAVE_CLASSES
+ * ------------
+ *
+ * When defined, the code to support classes, instances, methods, etc.
+ * is included in the build.
+ * Issue #202 Implement classes in the vm
+ *
+ *
+ * HAVE_ASSERT
+ * -----------
+ *
+ * When defined, the code to support the assert statement is included
+ * in the build.
+ *
+ *
+ * HAVE_GENERATORS
+ * ---------------
+ *
+ * When defined, the code to support the yield keyword's use for
+ * generator-iterators is included in the build.
+ * Issue #207 Add support for the yield keyword
+ *
+ *
+ * HAVE_BACKTICK
+ * -------------
+ *
+ * When defined, the code to support the backtick operation (`x`) is included
+ * in the build.
+ * REQUIRES stdio.h to have snprintf()
+ * Issue #244 Add support for the backtick operation (UNARY_CONVERT)
+ *
+ *
+ * HAVE_STRING_FORMAT
+ * ------------------
+ *
+ * When defined, the code to perform string formatting using the binary modulo
+ * operator is included in the build.
+ * REQUIRES stdio.h to have snprintf()
+ * Issue #205 Add support for string format operation
+ *
+ *
+ * HAVE_CLOSURES
+ * -------------
+ *
+ * When defined, the code to support function closures is included in the
+ * build.
+ * Issue #256 Add support for closures
+ *
+ *
+ * HAVE_BYTEARRAY
+ * --------------
+ *
+ * When defined, the code to support the bytearray type is included in the
+ * build.  NOTE: If this is defined, the bytearray class in src/lib/__bi.py
+ * must also be uncommented.
+ * Issue #289 Create bytearray datatype
+ *
+ *
+ * HAVE_DEBUG_INFO
+ * ---------------
+ *
+ * When defined, the code to support debug information in exception reports
+ * is included in the build.
+ * Issue #103 Add debug info to exception reports
+ *
+ *
+ * HAVE_SNPRINTF_FORMAT
+ * --------------------
+ *
+ * When defined, the string format operation is performed using C's snprintf().
+ * The snprintf() function and all its helper functions can take up program
+ * memory, so some people may choose to do without this.  
+ * You should define this when you need precise control over numeric formatting
+ * such as when you supply numbers between the '%' and the type specifier,
+ * like so::
+ *
+ *      printf "Number = %4d" % someNumber
+ *      pirntf "PI approx = %1.2" % 3.1415
+ */
+
+/* Check for dependencies */
+
+#if defined(HAVE_ASSERT) && !defined(HAVE_CLASSES)
+#error HAVE_ASSERT requires HAVE_CLASSES
+#endif
+
+
+#if defined(HAVE_GENERATORS) && !defined(HAVE_CLASSES)
+#error HAVE_GENERATORS requires HAVE_CLASSES
+#endif
+
+
+#if defined(HAVE_CLOSURES) && !defined(HAVE_DEFAULTARGS)
+#error HAVE_CLOSURES requires HAVE_DEFAULTARGS
+#endif
+
+
+#if defined(HAVE_BYTEARRAY) && !defined(HAVE_CLASSES)
+#error HAVE_BYTEARRAY requires HAVE_CLASSES
+#endif
+
+#if defined(HAVE_SNPRINTF_FORMAT) && !defined(HAVE_STRING_FORMAT)
+#error HAVE_SNPRINTF_FORMAT requires HAVE_STRING_FORMAT
+#endif /* __PM_EMPTY_PM_FEATURES_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/seglist.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,358 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x10
+
+
+/**
+ * \file
+ * \brief Segmented list data type and operations
+ *
+ * The segmented list is used to implement the Python
+ * List and Dict data types.
+ * The segmented list is used in preference to the linked list
+ * in order to reduce the memory overhead.
+ *
+ * Unused slots in the segments are expected to contain C_NULL.
+ *
+ * List implementation:
+ * When used in a List, the Seglist.currseg field points
+ * to the last segment in the list.
+ * The function seglist_appendItem() should be used to append
+ * items to the List.
+ * Inserting and deleting List items is a more complicated
+ * matter.
+ *
+ * Dict implementation:
+ * The currseg field is meaningless since rootseg always
+ * points to the current active segment.
+ * The function seglist_pushItem() should be used to put
+ * items in the Dict.
+ * A Dict uses one Seglist for keys and another for values.
+ * A Dict entry's (key, value) pair share the same index in
+ * the Seglist.
+ */
+
+
+#include "pm.h"
+
+
+/**
+ * Set this to 1 if seglist_clear() should manually free its segments.
+ * Set this to 0 if seglist_clear() should do nothing
+ * and let the GC reclaim objects.
+ */
+#define SEGLIST_CLEAR_SEGMENTS 1
+
+
+PmReturn_t
+seglist_appendItem(pSeglist_t pseglist, pPmObj_t pobj)
+{
+    return seglist_insertItem(pseglist, pobj, pseglist->sl_length);
+}
+
+
+PmReturn_t
+seglist_clear(pSeglist_t pseglist)
+{
+    pSegment_t pseg1 = C_NULL;
+    pSegment_t pseg2 = C_NULL;
+
+#if SEGLIST_CLEAR_SEGMENTS
+    /* Deallocate all linked segments */
+    pseg1 = ((pSeglist_t)pseglist)->sl_rootseg;
+    while (pseg1 != C_NULL)
+    {
+        pseg2 = pseg1->next;
+        PM_RETURN_IF_ERROR(heap_freeChunk((pPmObj_t)pseg1));
+        pseg1 = pseg2;
+    }
+#endif
+
+    /* Clear seglist fields */
+    ((pSeglist_t)pseglist)->sl_rootseg = C_NULL;
+    ((pSeglist_t)pseglist)->sl_lastseg = C_NULL;
+    ((pSeglist_t)pseglist)->sl_length = 0;
+
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+seglist_findEqual(pSeglist_t pseglist, pPmObj_t pobj, int16_t *r_index)
+{
+    pSegment_t pseg;
+    int8_t i = 0;
+    uint8_t segindex;
+
+    C_ASSERT(pseglist != C_NULL);
+    C_ASSERT(pobj != C_NULL);
+    C_ASSERT((*r_index >= 0));
+    C_ASSERT((*r_index == 0) || (*r_index < pseglist->sl_length));
+
+    /* Walk out to the starting segment */
+    pseg = pseglist->sl_rootseg;
+    for (i = (*r_index / SEGLIST_OBJS_PER_SEG); i > (int8_t)0; i--)
+    {
+        C_ASSERT(pseg != C_NULL);
+        pseg = pseg->next;
+    }
+
+    /* Set the starting index within the segment */
+    segindex = *r_index % SEGLIST_OBJS_PER_SEG;
+
+    /* Search the remaining segments */
+    for (; pseg != C_NULL; pseg = pseg->next)
+    {
+        while (segindex < SEGLIST_OBJS_PER_SEG)
+        {
+            /* If past the end of the seglist, return no item found */
+            if (*r_index >= pseglist->sl_length)
+            {
+                return PM_RET_NO;
+            }
+
+            /* If items are equal, return with index of found item */
+            if (obj_compare(pobj, pseg->s_val[segindex]) == C_SAME)
+            {
+                return PM_RET_OK;
+            }
+
+            /* Proceed to next item */
+            segindex++;
+            (*r_index)++;
+        }
+
+        /* Proceed to next segment */
+        segindex = 0;
+    }
+    return PM_RET_NO;
+}
+
+
+PmReturn_t
+seglist_getItem(pSeglist_t pseglist, int16_t index, pPmObj_t *r_pobj)
+{
+    pSegment_t pseg;
+    int16_t i;
+
+    C_ASSERT(pseglist != C_NULL);
+    C_ASSERT(index >= 0);
+    C_ASSERT(index < pseglist->sl_length);
+
+    /* Walk out to the proper segment */
+    pseg = pseglist->sl_rootseg;
+    C_ASSERT(pseg != C_NULL);
+    for (i = (index / SEGLIST_OBJS_PER_SEG); i > 0; i--)
+    {
+        pseg = pseg->next;
+        C_ASSERT(pseg != C_NULL);
+    }
+
+    /* Return ptr to obj in this seg at the index */
+    *r_pobj = pseg->s_val[index % SEGLIST_OBJS_PER_SEG];
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+seglist_insertItem(pSeglist_t pseglist, pPmObj_t pobj, int16_t index)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pSegment_t pseg = C_NULL;
+    pPmObj_t pobj1 = C_NULL;
+    pPmObj_t pobj2 = C_NULL;
+    int8_t indx = (int8_t)0;
+    int16_t i = 0;
+    uint8_t *pchunk;
+
+    C_ASSERT(index <= pseglist->sl_length);
+
+    /* If a new seg is needed */
+    if ((pseglist->sl_length % SEGLIST_OBJS_PER_SEG) == 0)
+    {
+        /* Alloc and init new segment */
+        retval = heap_getChunk(sizeof(Segment_t), &pchunk);
+        PM_RETURN_IF_ERROR(retval);
+        pseg = (pSegment_t)pchunk;
+        OBJ_SET_TYPE(pseg, OBJ_TYPE_SEG);
+        sli_memset((unsigned char *)pseg->s_val,
+                   0, SEGLIST_OBJS_PER_SEG * sizeof(pPmObj_t));
+        pseg->next = C_NULL;
+
+        /* If this is the first seg, set as root */
+        if (pseglist->sl_rootseg == C_NULL)
+        {
+            pseglist->sl_rootseg = pseg;
+        }
+
+        /* Else append the seg to the end */
+        else
+        {
+            pseglist->sl_lastseg->next = pseg;
+        }
+
+        /* Either way, this is now the last segment */
+        pseglist->sl_lastseg = pseg;
+    }
+
+    /* Walk out to the segment for insertion */
+    pseg = pseglist->sl_rootseg;
+    C_ASSERT(pseg != C_NULL);
+    for (i = (index / SEGLIST_OBJS_PER_SEG); i > 0; i--)
+    {
+        pseg = pseg->next;
+        C_ASSERT(pseg != C_NULL);
+    }
+
+    /* Insert obj and ripple copy all those afterward */
+    indx = index % SEGLIST_OBJS_PER_SEG;;
+    pobj1 = pobj;
+    while (pobj1 != C_NULL)
+    {
+        pobj2 = pseg->s_val[indx];
+        pseg->s_val[indx] = pobj1;
+        pobj1 = pobj2;
+        indx++;
+
+        /* If indx exceeds this seg, go to next seg */
+        if ((indx >= SEGLIST_OBJS_PER_SEG) && (pobj1 != C_NULL))
+        {
+            pseg = pseg->next;
+            C_ASSERT(pseg != C_NULL);
+            indx = (int8_t)0;
+        }
+    }
+    pseglist->sl_length++;
+    return retval;
+}
+
+
+PmReturn_t
+seglist_new(pSeglist_t *r_pseglist)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    retval = heap_getChunk(sizeof(Seglist_t), (uint8_t **)r_pseglist);
+    PM_RETURN_IF_ERROR(retval);
+
+    OBJ_SET_TYPE(*r_pseglist, OBJ_TYPE_SGL);
+    (*r_pseglist)->sl_rootseg = C_NULL;
+    (*r_pseglist)->sl_lastseg = C_NULL;
+    (*r_pseglist)->sl_length = 0;
+    return retval;
+}
+
+
+PmReturn_t
+seglist_setItem(pSeglist_t pseglist, pPmObj_t pobj, int16_t index)
+{
+    pSegment_t pseg;
+    int16_t i;
+
+    C_ASSERT(index <= pseglist->sl_length);
+
+    /* Walk out to the proper segment */
+    pseg = pseglist->sl_rootseg;
+    C_ASSERT(pseg != C_NULL);
+    for (i = (index / SEGLIST_OBJS_PER_SEG); i > 0; i--)
+    {
+        pseg = pseg->next;
+        C_ASSERT(pseg != C_NULL);
+    }
+
+    /* Set item in this seg at the index */
+    pseg->s_val[index % SEGLIST_OBJS_PER_SEG] = pobj;
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+seglist_removeItem(pSeglist_t pseglist, uint16_t index)
+{
+    pSegment_t pseg;
+    int16_t i,
+      k;
+
+    C_ASSERT(index < pseglist->sl_length);
+
+    /* Walk through the segments */
+    pseg = pseglist->sl_rootseg;
+    C_ASSERT(pseg != C_NULL);
+    for (i = (index / SEGLIST_OBJS_PER_SEG); i > 0; i--)
+    {
+        pseg = pseg->next;
+        C_ASSERT(pseg != C_NULL);
+    }
+
+    /*
+     * pseg now points to the correct segment of the item to be removed, so
+     * start ripple copying all following items up to the last
+     * in the last segment
+     */
+
+    for (i = index; i < ((pseglist->sl_length) - 1); i++)
+    {
+        k = i % SEGLIST_OBJS_PER_SEG;
+
+        /* Copy element i+1 to slot i */
+        if ((k + 1) == SEGLIST_OBJS_PER_SEG)
+        {
+            /* Source is first item in next segment */
+            pseg->s_val[i % SEGLIST_OBJS_PER_SEG] = (pseg->next)->s_val[0];
+            pseg = pseg->next;
+        }
+        else
+        {
+            /* Source and target are in the same segment */
+            pseg->s_val[k] = pseg->s_val[k + 1];
+        }
+    }
+
+    pseglist->sl_length -= 1;
+
+    /* Remove the last segment if it was emptied */
+    if (pseglist->sl_length % SEGLIST_OBJS_PER_SEG == 0)
+    {
+        pseg = pseglist->sl_rootseg;
+
+        /* Find the segment before the last */
+        for (i = 0; i < ((pseglist->sl_length - 1) / SEGLIST_OBJS_PER_SEG);
+             i++)
+        {
+            pseg = pseg->next;
+            C_ASSERT(pseg != C_NULL);
+        }
+        if (pseg->next == C_NULL)
+        {
+            /*
+             * Seglist is now completely empty and the last segment can be
+             * recycled.
+             */
+#if SEGLIST_CLEAR_SEGMENTS
+            PM_RETURN_IF_ERROR(heap_freeChunk((pPmObj_t)pseg));
+#endif
+            pseglist->sl_lastseg = C_NULL;
+            pseglist->sl_rootseg = C_NULL;
+        }
+        else
+        {
+            /* At least one segment remains */
+            pseglist->sl_lastseg = pseg;
+            pseg->next = C_NULL;
+        }
+    }
+    else
+    {
+        /* Zero out the now unused slot */
+        pseg->s_val[pseglist->sl_length % SEGLIST_OBJS_PER_SEG] = C_NULL;
+    }
+
+    return PM_RET_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/seglist.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,160 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __SEGLIST_H__
+#define __SEGLIST_H__
+
+
+/**
+ * \file
+ * \brief Segmented List data structure
+ *
+ * A seglist is a linked list of segments.
+ * A segment is an array of ptrs to objects
+ * (with a pointer to the next segment).
+ * Seglists are used to implement Lists and Dicts.
+ *
+ * This implementation of Seglist is straight.
+ * That is, the next pointer in the final segment
+ * contains C_NULL.
+ *
+ * This implementation of Seglist is dense.
+ * That is, there are no gaps in a segment.
+ * All entries point to an object, except entries
+ * that are beyond the index of the last item.
+ */
+
+
+/** Defines the length of the object array in a segment */
+#define SEGLIST_OBJS_PER_SEG 8
+
+
+/** Segment - an array of ptrs to objs */
+typedef struct Segment_s
+{
+    /** object descriptor */
+    PmObjDesc_t od;
+    /** array of ptrs to objs */
+    pPmObj_t s_val[SEGLIST_OBJS_PER_SEG];
+    /** ptr to next segment */
+    struct Segment_s *next;
+} Segment_t,
+ *pSegment_t;
+
+
+/** Seglist - linked list of segments with current index info */
+typedef struct Seglist_s
+{
+    /** object descriptor */
+    PmObjDesc_t od;
+    /** index of (one past) last obj in last segment */
+    int16_t sl_length;
+    /** ptr to first segment in list */
+    pSegment_t sl_rootseg;
+    /** ptr to last segment */
+    pSegment_t sl_lastseg;
+} Seglist_t,
+ *pSeglist_t;
+
+
+/**
+ * Puts the new object at the end of the list.
+ * This is intended for the List type where
+ * the List index matches the order of the Seglist index.
+ * Makes room if necessary by adding new segments.
+ *
+ * @param pseglist Ptr to seglist
+ * @param pobj Pointer to object to append
+ * @return Return status
+ */
+PmReturn_t seglist_appendItem(pSeglist_t pseglist, pPmObj_t pobj);
+
+/**
+ * Clears the the seglist by unlinking the root segment.
+ *
+ * @param pseglist Ptr to seglist to empty
+ */
+PmReturn_t seglist_clear(pSeglist_t pseglist);
+
+/**
+ * Finds the first obj equal to pobj in the seglist.
+ * Starts searching the list at the given segnum and indx.
+ *
+ * @param   pseglist The seglist to search
+ * @param   pobj The object to match
+ * @param   r_index Return arg; the index of where to start the search.
+ *          If a match is found, return the index by reference.
+ *          If no match is found, this value is undefined.
+ * @return  Return status; PM_RET_OK means a matching object
+ *          was found.  PM_RET_ERR otherwise.
+ */
+PmReturn_t seglist_findEqual(pSeglist_t pseglist,
+                             pPmObj_t pobj, int16_t *r_index);
+
+/**
+ * Gets the item in the seglist at the given coordinates.
+ * The segment number and the index within the segment
+ * are the coordinates of the object to get.
+ *
+ * @param   pseglist Ptr to seglist to scan
+ * @param   index Index of item to get
+ * @param   r_pobj Return arg; Ptr to object at the index
+ * @return  Return status; PM_RET_OK if object found.
+ *          PM_RET_ERR otherwise.
+ */
+PmReturn_t seglist_getItem(pSeglist_t pseglist,
+                           int16_t index, pPmObj_t *r_pobj);
+
+/**
+ * Allocates a new empty seglist
+ *
+ * @param   r_pseglist return; Address of ptr to new seglist
+ * @return  Return status
+ */
+PmReturn_t seglist_new(pSeglist_t *r_pseglist);
+
+
+/**
+ * Puts the item in the next available slot in the first available segment.
+ * This is intended for the Dict type where
+ * the Seglist index is insignificant.
+ * Pushing an object assures it will be found early
+ * during a call to seglist_findEqual().
+ *
+ * @param   pseglist Ptr to seglist in which object is placed.
+ * @param   pobj Ptr to object which is inserted.
+ * @param   index Index into seglist before which item is inserted
+ * @return  Return status; PM_RET_OK if the item was inserted.
+ *              Any error condition comes from heap_getChunk.
+ */
+PmReturn_t seglist_insertItem(pSeglist_t pseglist,
+                              pPmObj_t pobj, int16_t index);
+
+/**
+ * Puts the item in the designated slot and segment.
+ * This is intended to be used after seglist_findEqual()
+ * returns the proper indeces.
+ *
+ * @param   pseglist Ptr to seglist in which object is placed.
+ * @param   pobj Ptr to object which is set.
+ * @param   index Index into seglist of where to put object.
+ * @return  Return status; PM_RET_OK if object is set.
+ *              PM_RET_ERR otherwise.
+ */
+PmReturn_t seglist_setItem(pSeglist_t pseglist, pPmObj_t pobj, int16_t index);
+
+/**
+ * Removes the item at the given index.
+ *
+ * @param   pseglist Ptr to seglist in which object is removed.
+ * @param   index Index into seglist of where to put object.
+ * @return  Return status
+ */
+PmReturn_t seglist_removeItem(pSeglist_t pseglist, uint16_t index);
+
+#endif /* __SEGLIST_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/seq.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,275 @@
+/*
+# This file is Copyright 2006 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x14
+
+
+/**
+ * \file
+ * \brief Sequence
+ *
+ * Functions that operate on sequences
+ */
+
+
+#include "pm.h"
+
+
+/*
+ * Compares two sequence objects
+ * Assumes both objects are of same type (guaranteed by obj_compare)
+ */
+int8_t
+seq_compare(pPmObj_t pobj1, pPmObj_t pobj2)
+{
+    int16_t l1;
+    int16_t l2;
+    pPmObj_t pa;
+    pPmObj_t pb;
+    PmReturn_t retval;
+    int8_t retcompare;
+
+    /* Get the lengths of supported types or return differ */
+    if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_TUP)
+    {
+        l1 = ((pPmTuple_t)pobj1)->length;
+        l2 = ((pPmTuple_t)pobj2)->length;
+    }
+    else if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_LST)
+    {
+        l1 = ((pPmList_t)pobj1)->length;
+        l2 = ((pPmList_t)pobj2)->length;
+    }
+
+#ifdef HAVE_BYTEARRAY
+    else if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_BYA)
+    {
+        /* Return if the lengths differ */
+        l1 = ((pPmBytearray_t)pobj1)->length;
+        l2 = ((pPmBytearray_t)pobj2)->length;
+        if (l1 != l2)
+        {
+            return C_DIFFER;
+        }
+
+        return sli_strncmp((char const *)&(((pPmBytes_t)((pPmBytearray_t)pobj1)->val)->val),
+                           (char const *)&(((pPmBytes_t)((pPmBytearray_t)pobj2)->val)->val),
+                           l1)
+               ? C_DIFFER : C_SAME;
+    }
+#endif /* HAVE_BYTEARRAY */
+
+    else
+    {
+        return C_DIFFER;
+    }
+
+    /* Return if the lengths differ */
+    if (l1 != l2)
+    {
+        return C_DIFFER;
+    }
+
+    /* Compare all items in the sequences */
+    while (--l1 >= 0)
+    {
+        retval = seq_getSubscript(pobj1, l1, &pa);
+        if (retval != PM_RET_OK)
+        {
+            return C_DIFFER;
+        }
+        retval = seq_getSubscript(pobj2, l1, &pb);
+        if (retval != PM_RET_OK)
+        {
+            return C_DIFFER;
+        }
+        retcompare = obj_compare(pa, pb);
+        if (retcompare != C_SAME)
+        {
+            return retcompare;
+        }
+    }
+
+    return C_SAME;
+}
+
+
+/* Returns the length of the sequence */
+PmReturn_t
+seq_getLength(pPmObj_t pobj, uint16_t *r_index)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    switch (OBJ_GET_TYPE(pobj))
+    {
+        case OBJ_TYPE_STR:
+            *r_index = ((pPmString_t)pobj)->length;
+            break;
+
+        case OBJ_TYPE_TUP:
+            *r_index = ((pPmTuple_t)pobj)->length;
+            break;
+
+        case OBJ_TYPE_LST:
+            *r_index = ((pPmList_t)pobj)->length;
+            break;
+
+#ifdef HAVE_BYTEARRAY
+        case OBJ_TYPE_BYA:
+            *r_index = ((pPmBytearray_t)pobj)->length;
+            break;
+#endif /* HAVE_BYTEARRAY */
+
+        case OBJ_TYPE_DIC:
+            *r_index = ((pPmDict_t)pobj)->length;
+            break;
+
+        default:
+            /* Raise TypeError, non-sequence object */
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            break;
+    }
+
+    return retval;
+}
+
+
+/* Returns the object sequence[index] */
+PmReturn_t
+seq_getSubscript(pPmObj_t pobj, int16_t index, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval;
+    pSeglist_t pkeys;
+    uint8_t c;
+
+    switch (OBJ_GET_TYPE(pobj))
+    {
+        case OBJ_TYPE_STR:
+            /* Adjust for negative index */
+            if (index < 0)
+            {
+                index += ((pPmString_t)pobj)->length;
+            }
+
+            /* Raise IndexError if index is out of bounds */
+            if ((index < 0) || (index > ((pPmString_t)pobj)->length))
+            {
+                PM_RAISE(retval, PM_RET_EX_INDX);
+                break;
+            }
+
+            /* Get the character from the string */
+            c = ((pPmString_t)pobj)->val[index];
+
+            /* Create a new string from the character */
+            retval = string_newFromChar(c, r_pobj);
+            break;
+
+        case OBJ_TYPE_TUP:
+            /* Get the tuple item */
+            retval = tuple_getItem(pobj, index, r_pobj);
+            break;
+
+        case OBJ_TYPE_LST:
+            /* Get the list item */
+            retval = list_getItem(pobj, index, r_pobj);
+            break;
+
+#ifdef HAVE_BYTEARRAY
+        case OBJ_TYPE_BYA:
+            retval = bytearray_getItem(pobj, index, r_pobj);
+            break;
+#endif /* HAVE_BYTEARRAY */
+
+        /* Issue #176 Add support to iterate over keys in a dict */
+        case OBJ_TYPE_DIC:
+            pkeys = ((pPmDict_t)pobj)->d_keys;
+            retval = seglist_getItem(pkeys, index, r_pobj);
+            break;
+
+        default:
+            /* Raise TypeError, unsubscriptable object */
+            PM_RAISE(retval, PM_RET_EX_TYPE);
+            break;
+    }
+
+    return retval;
+}
+
+
+PmReturn_t
+seqiter_getNext(pPmObj_t pobj, pPmObj_t *r_pitem)
+{
+    PmReturn_t retval;
+    uint16_t length;
+
+    C_ASSERT(pobj != C_NULL);
+    C_ASSERT(*r_pitem != C_NULL);
+    C_ASSERT(OBJ_GET_TYPE(pobj) == OBJ_TYPE_SQI);
+
+    /*
+     * Raise TypeError if sequence iterator's object is not a sequence
+     * otherwise, the get sequence's length
+     */
+    retval = seq_getLength(((pPmSeqIter_t)pobj)->si_sequence, &length);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Raise StopIteration if at the end of the sequence */
+    if (((pPmSeqIter_t)pobj)->si_index == length)
+    {
+        /* Make null the pointer to the sequence */
+        ((pPmSeqIter_t)pobj)->si_sequence = C_NULL;
+        PM_RAISE(retval, PM_RET_EX_STOP);
+        return retval;
+    }
+
+    /* Get the item at the current index */
+    retval = seq_getSubscript(((pPmSeqIter_t)pobj)->si_sequence,
+                              ((pPmSeqIter_t)pobj)->si_index, r_pitem);
+
+    /* Increment the index */
+    ((pPmSeqIter_t)pobj)->si_index++;
+
+    return retval;
+}
+
+
+PmReturn_t
+seqiter_new(pPmObj_t pobj, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval;
+    uint8_t *pchunk;
+    pPmSeqIter_t psi;
+
+    C_ASSERT(pobj != C_NULL);
+    C_ASSERT(*r_pobj != C_NULL);
+
+    /* Raise a TypeError if pobj is not a sequence */
+    if ((OBJ_GET_TYPE(pobj) != OBJ_TYPE_STR)
+        && (OBJ_GET_TYPE(pobj) != OBJ_TYPE_TUP)
+        && (OBJ_GET_TYPE(pobj) != OBJ_TYPE_LST)
+        && (OBJ_GET_TYPE(pobj) != OBJ_TYPE_DIC))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Alloc a chunk for the sequence iterator obj */
+    retval = heap_getChunk(sizeof(PmSeqIter_t), &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Set the sequence iterator's fields */
+    psi = (pPmSeqIter_t)pchunk;
+    OBJ_SET_TYPE(psi, OBJ_TYPE_SQI);
+    psi->si_sequence = pobj;
+    psi->si_index = 0;
+
+    *r_pobj = (pPmObj_t)psi;
+    return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/seq.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,86 @@
+/*
+# This file is Copyright 2006 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __SEQ_H__
+#define __SEQ_H__
+
+
+/**
+ * \file
+ * \brief Sequence Header
+ */
+
+
+/**
+ * Sequence Iterator Object
+ *
+ * Instances of this object are created by GET_ITER and used by FOR_ITER.
+ * Stores a pointer to a sequence and an index int16_t.
+ */
+typedef struct PmSeqIter_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Sequence object */
+    pPmObj_t si_sequence;
+
+    /** Index value */
+    int16_t si_index;
+} PmSeqIter_t,
+ *pPmSeqIter_t;
+
+
+/**
+ * Compares two sequences for equality
+ *
+ * @param   pobj1 Ptr to first sequence.
+ * @param   pobj2 Ptr to second sequence.
+ * @return  C_SAME if the seuqences are equivalent, C_DIFFER otherwise.
+ */
+int8_t seq_compare(pPmObj_t pobj1, pPmObj_t pobj2);
+
+/**
+ * Returns the length of the sequence
+ *
+ * @param   pobj Ptr to  sequence.
+ * @param   r_index Return arg, length of sequence
+ * @return  Return status
+ */
+PmReturn_t seq_getLength(pPmObj_t pobj, uint16_t *r_index);
+
+/**
+ * Returns the object from sequence[index]
+ *
+ * @param   pobj Ptr to sequence object to get object from
+ * @param   index Int index into the sequence
+ * @param   r_pobj Return arg, object from sequence
+ * @return  Return status
+ */
+PmReturn_t seq_getSubscript(pPmObj_t pobj, int16_t index, pPmObj_t *r_pobj);
+
+/**
+ * Returns the next item from the sequence iterator object
+ *
+ * @param   pobj Ptr to sequence iterator.
+ * @param   r_pitem Return arg, pointer to next item from sequence.
+ * @return  Return status.
+ */
+PmReturn_t seqiter_getNext(pPmObj_t pobj, pPmObj_t *r_pitem);
+
+
+/**
+ * Returns a new sequence iterator object
+ *
+ * @param   pobj Ptr to sequence.
+ * @param   r_pobj Return by reference, new sequence iterator
+ * @return  Return status.
+ */
+PmReturn_t seqiter_new(pPmObj_t pobj, pPmObj_t *r_pobj);
+
+#endif /* __SEQ_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/sli.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,442 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x11
+
+
+/**
+ * \file
+ * \brief Standard Library Interface
+ *
+ * PyMite requires a few functions from a few different
+ * standard C libraries (memory, string, etc).
+ */
+
+
+#include "pm.h"
+
+
+/** use Duff's Device or simple for-loop for memcpy. */
+#define USE_DUFFS_DEVICE    0
+
+
+#if !HAVE_STRING_H
+
+void *
+sli_memcpy(unsigned char *to, unsigned char const *from, unsigned int n)
+{
+    unsigned char *tobak;
+
+    /* Store init value of to */
+    tobak = to;
+
+#if USE_DUFFS_DEVICE
+    if (n > 0)
+    {
+        switch (n & 0x7)
+            do
+            {
+            case 0:
+                *to++ = *from++;
+            case 7:
+                *to++ = *from++;
+            case 6:
+                *to++ = *from++;
+            case 5:
+                *to++ = *from++;
+            case 4:
+                *to++ = *from++;
+            case 3:
+                *to++ = *from++;
+            case 2:
+                *to++ = *from++;
+            case 1:
+                *to++ = *from++;
+            }
+            while ((n -= 8) > 0);
+    }
+#else
+    for (; n > 0; n--)
+    {
+        *to = *from;
+        from++;
+        to++;
+    }
+#endif /* USE_DUFFS_DEVICE */
+    return tobak;
+}
+
+
+int
+sli_strlen(char const *s)
+{
+    char const *si = s;
+    int len = 0;
+
+    while (*si++)
+    {
+        len++;
+    }
+    return len;
+}
+
+
+int
+sli_strcmp(char const *s1, char const *s2)
+{
+    /* While not at either strings' end and they're same */
+    while ((*s1 != C_NULL) && (*s2 != C_NULL) && (*s1 == *s2))
+    {
+        s1++;
+        s2++;
+    }
+
+    /* Return string difference */
+    return *s1 - *s2;
+}
+
+
+int
+sli_strncmp(char const *s1, char const *s2, unsigned int n)
+{
+    unsigned int i = 0;
+
+    if (n == 0)
+    {
+        return 0;
+    }
+
+    /* Scan n bytes in string */
+    for (i = 0; i < n; i++)
+    {
+        /* If bytes differ, return difference */
+        if (s1[i] != s2[i])
+        {
+            return s1[i] - s2[i];
+        }
+    }
+    return 0;
+}
+
+#endif /* HAVE_STRING_H */
+
+
+/*
+ * This function is moved outside of HAVE_STRING_H because the one in string.h
+ * will not accept a null value for the second arg
+ */
+void
+sli_memset(unsigned char *dest, char const val, unsigned int n)
+{
+    unsigned int i;
+
+    for (i = 0; i < n; i++)
+    {
+        *dest = (unsigned char)val;
+        dest++;
+    }
+}
+
+void
+sli_puts(uint8_t * s)
+{
+    uint8_t *ps = s;
+    uint8_t c;
+
+    c = *ps;
+    ps++;
+    while (c != '\0')
+    {
+        plat_putByte(c);
+        c = *ps;
+        ps++;
+    }
+}
+
+
+PmReturn_t
+sli_ltoa10(int32_t value, uint8_t *buf, uint8_t buflen)
+{
+    int32_t const decimal_places[] = { 1000000000, 100000000, 10000000, 1000000,
+                                       100000, 10000, 1000, 100, 10, 1 };
+    int32_t decimal_place;
+    int32_t number;
+    uint8_t c;
+    uint8_t printed_one = C_FALSE;
+    uint8_t i;
+    uint8_t j;
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(buflen >= 12);
+
+    number = value;
+    if (number == 0)
+    {
+        buf[0] = '0';
+        buf[1] = '\0';
+        return retval;
+    }
+
+    /* Special case (can't convert it to positive value) */
+    if (number == -2147483648)
+    {
+        sli_memcpy(buf, (unsigned char *)"-2147483648", 11);
+        return PM_RET_OK;
+    }
+
+    j = 0;
+    if (number < 0)
+    {
+        buf[0] = '-';
+        j++;
+        number = -number;
+    }
+
+    for (i = 0; i < 10; i++)
+    {
+        decimal_place = decimal_places[i];
+        c = '0';
+        while (number >= decimal_place)
+        {
+            number -= decimal_place;
+            c++;
+        }
+        if ((c != '0') || printed_one)
+        {
+            buf[j++] = c;
+            printed_one = C_TRUE;
+        }
+    }
+    buf[j] = '\0';
+
+    return retval;
+}
+
+char const * const hexChars = "0123456789abcdef";
+
+/* MUST show leading zeros because callers don't keep track */
+PmReturn_t
+sli_btoa16(uint8_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase)
+{
+    C_ASSERT(buflen >= 3);
+
+    if (upperCase) upperCase = 'A' - 'a';
+
+    buf[0] = (value >> 4) > 9 
+             ? hexChars[value >> 4] + upperCase
+             : hexChars[value >> 4];
+    buf[1] = (value & 0x0F) > 9
+             ? hexChars[value & 0x0F] + upperCase
+             : hexChars[value & 0x0F];
+    buf[2] = '\0';
+
+    return PM_RET_OK;
+}
+
+
+/* Does NOT show leading zeroes */
+PmReturn_t
+sli_ltoa16(int32_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase)
+{
+    int8_t i;
+    uint8_t j = 0;
+    uint8_t showZero = C_FALSE;
+    uint8_t nibble;
+
+    C_ASSERT(buflen >= 9);
+
+    if (upperCase) upperCase = 'A' - 'a';
+
+    for (i = 28; i >= 0; i -= 4)
+    {
+        nibble = ((value >> i) & 0xF);
+        if ((nibble == 0) && !showZero) continue;
+        buf[j++] = (nibble > 9) 
+                   ? hexChars[nibble] + upperCase
+                   : hexChars[nibble];
+        showZero = C_TRUE;
+    }
+    buf[j] = '\0';
+
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+sli_ptoa16(intptr_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase)
+{
+    PmReturn_t retval;
+    int8_t i;
+    int8_t j;
+
+    C_ASSERT(buflen >= 2 * sizeof(intptr_t) + 1);
+
+    /* Print the hex value, most significant byte first */
+    for (j = 0, i = 8 * sizeof(intptr_t) - 8; i >= 0; i -= 8, j += 2)
+    {
+        retval = sli_btoa16((value >> i) & 0xFF, &buf[j], buflen - j, upperCase);
+        PM_BREAK_IF_ERROR(retval);
+    }
+
+    return retval;
+}
+
+
+typedef union {
+    int32_t L;
+    float F;
+} LF_t;
+
+
+/* The buf MUST be at least 15 bytes long */
+PmReturn_t
+sli_ftoa(float f, uint8_t *buf, uint8_t buflen)
+{
+    uint32_t mantissa, int_part, frac_part;
+    int16_t exp2;
+    LF_t x;
+    uint8_t *p;
+    int8_t adj = 0;
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(buflen >= 15);
+
+    if (f == 0.0)
+    {
+        buf[0] = '0';
+        buf[1] = '.';
+        buf[2] = '0';
+        buf[3] = '\0';
+        return PM_RET_OK;
+    }
+    x.F = f;
+
+    exp2 = (0xFF & (x.L >> 23)) - 127;
+    mantissa = (x.L & 0xFFFFFF) | 0x800000;
+    frac_part = 0;
+    int_part = 0;
+    p = buf;
+
+    /* Adjust large exponents using the approximation: 2**10 == k*10**3 */
+    while (exp2 >= 31)
+    {
+        /* Reduce the binary exponent here (incr the decimal exponent below) */
+        exp2 -=  10;
+        adj++;
+
+        /*
+         * To use the approximation above, the mantissa must be multiplied by k
+         * where k = 1.024 ~= (1 + 12583/(2**19))
+         * Divide first to avoid integer overflow (the mantissa is 24 bits)
+         */
+        mantissa += ((mantissa >> 6) * 12583) >> 13;
+    }
+
+    if (exp2 < -23)
+    {
+        // Unable to handle large negative exponents at this time
+        *p++ = '?';
+        return PM_RET_OK;
+    }
+    else if (exp2 >= 23)
+    {
+        int_part = mantissa << (exp2 - 23);
+    }
+    else if (exp2 >= 0)
+    {
+        int_part = mantissa >> (23 - exp2);
+        frac_part = (mantissa << (exp2 + 1)) & 0xFFFFFF;
+    }
+    else /* if (exp2 < 0) */
+    {
+        frac_part = (mantissa & 0xFFFFFF) >> -(exp2 + 1);
+    }
+
+    if (x.L < 0)
+    {
+        *p++ = '-';
+    }
+
+    if (int_part == 0)
+    {
+        *p++ = '0';
+    }
+    else
+    {
+        retval = sli_ltoa10(int_part, p, buflen - (p - buf));
+        PM_RETURN_IF_ERROR(retval);
+        while (*p) p++;
+    }
+    *p++ = '.';
+
+    if (frac_part == 0)
+    {
+        *p++ = '0';
+    }
+    else
+    {
+        char m, max;
+
+        max = buflen - (p - buf) - 1;
+        if (max > 6)
+        {
+            max = 6;
+        }
+
+        /* Print fractional part */
+        for (m = 0; m < max; m++)
+        {
+            frac_part *= 10;
+            *p++ = '0' + (frac_part >> 24);
+            frac_part &= 0xFFFFFF;
+        }
+
+        /* Remove ending zeroes */
+        //for (--p; p[0] == '0' && p[-1] != '.'; --p);
+        //++p;
+    }
+
+    /*
+     * If the exponent is large (adjustment took place above),
+     * normalize the string to scientific notation
+     */
+    if (adj != 0)
+    {
+        uint8_t i;
+
+        /* Shift chars to make room for the new decimal point */
+        i = (p - buf + 1);
+        i = (i > (buflen - 1)) ? buflen - 1 : i;
+        for (; i > 1; i--)
+        {
+            buf[i] = buf[i-1];
+        }
+
+        /* Find the index of the old decimal point */
+        for (i = 6; (buf[i] != '.') && (i < 15); i++);
+
+        /* Set the new decimal point (normalized) */
+        buf[1] = '.';
+
+        /*
+         * Adjust the decimal exponent (3 decimal places for every 10 bits)
+         * and add the amount for the normalization
+         */
+        p = &buf[8];
+        *p++ = 'e';
+        *p++ = '+';
+        retval = sli_ltoa10(3 * adj + (i - 2), p, buflen - (p - buf));
+        PM_RETURN_IF_ERROR(retval);
+        while (*p) p++;
+    }
+
+    *p = '\0';
+
+    return PM_RET_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/sli.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,174 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __SLI_H__
+#define __SLI_H__
+
+
+/**
+ * \file
+ * \brief Standard Library Interface
+ *
+ * PyMite requires a few functions from a few different
+ * standard C libraries (memory, string, etc).
+ * If your microcontroller has these libraries,
+ * set the constant to 1 for each library available.
+ * This will cause a macro to be defined which wraps
+ * the function for use by PyMite.
+ * Otherwise, leave the constant as 0, and PyMite will
+ * use the function defined in sli.c
+ * Some of the functions in sli.c will need to be ported
+ * to the target system.
+ */
+
+
+/**
+ * If the compiler has string.h, set HAVE_STRING to 1;
+ * otherwise, leave it 0 and the sli functions will be used.
+ */
+#define HAVE_STRING_H 0
+
+
+/*
+ * This section creates a macro or a function prototype
+ * for each library based on the corresponding constant.
+ * For example, if HAVE_STRING_H is defined to non-zero,
+ * the system <string.h> file will be included,
+ * and a macro "sli_strcmp" will be created to wrap the strcmp()
+ * function.  But if HAVE_STRING is zero, the sli_strcmp()
+ * prototype will be declared and sli_strcmp() must be
+ * implemented in sli.c
+ */
+
+#if HAVE_STRING_H
+
+#include <string.h>
+
+#define sli_memcpy(to, from, n) memcpy((to), (from), (n))
+#define sli_strcmp(s1, s2)      strcmp((s1),(s2))
+#define sli_strlen(s)           strlen(s)
+#define sli_strncmp(s1, s2, n)  strncmp((s1),(s2),(n))
+
+#else
+
+/**
+ * Copies a block of memory in RAM.
+ *
+ * @param   to The destination address.
+ * @param   from The source address.
+ * @param   n The number of bytes to copy.
+ * @return  The initial pointer value of the destination
+ * @see     mem_copy
+ */
+void *sli_memcpy(unsigned char *to, unsigned char const *from, unsigned int n);
+
+/**
+ * Compares two strings.
+ *
+ * @param   s1 Ptr to string 1.
+ * @param   s2 Ptr to string 2.
+ * @return  value that is less then, equal to or greater than 0
+ *          depending on whether s1's encoding is
+ *          less than, equal to, or greater than s2's.
+ */
+int sli_strcmp(char const *s1, char const *s2);
+
+/**
+ * Obtain string length.
+ *
+ * @param   s ptr to string.
+ * @return  number of bytes in string.
+ */
+int sli_strlen(char const *s);
+
+/**
+ * Compare strings for a specific length.
+ *
+ * @param   s1 ptr to string 1.
+ * @param   s2 ptr to string 2.
+ * @param   n number of chars to compare
+ * @return  value that is less then, equal to or greater than 0
+ *          depending on whether s1's encoding is
+ *          less than, equal to, or greater than s2's.
+ */
+int sli_strncmp(char const *s1, char const *s2, unsigned int n);
+
+#endif /* HAVE_STRING_H */
+
+/**
+ * Copy a value repeatedly into a block of memory
+ *
+ * @param   dest the destination address.
+ * @param   val the value.
+ * @param   n the number of bytes to copy.
+ * @return  Nothing
+ * @see     memset
+ */
+void sli_memset(unsigned char *dest, const char val, unsigned int n);
+
+/**
+ * Prints a string to stdout (using plat_putByte)
+ *
+ * @param s Pointer to the C string to print
+ */
+void sli_puts(uint8_t * s);
+
+/**
+ * Formats a 32-bit signed int as a decimal value.
+ *
+ * @param value the 32-bit signed value
+ * @param buf a pointer to where the formatted string goes
+ * @param buflen the length of the given buffer in bytes
+ * @return a pointer to the string. 
+ */
+PmReturn_t sli_ltoa10(int32_t value, uint8_t *buf, uint8_t buflen);
+
+/**
+ * Formats an 8-bit int as a hexadecimal value.
+ *
+ * @param value the 8-bit value
+ * @param buf a pointer to where the formatted string goes
+ * @param buflen the length of the given buffer in bytes
+ * @param upperCase when zero, hex chars rendered lowercase, else uppercase
+ * @return Always PM_RET_OK
+ */
+PmReturn_t sli_btoa16(uint8_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase);
+
+/**
+ * Formats a 32-bit signed int as a hexadecimal value.
+ *
+ * @param value the 32-bit signed value
+ * @param buf a pointer to where the formatted string goes
+ * @param buflen the length of the given buffer in bytes
+ * @param upperCase when zero, hex chars rendered lowercase, else uppercase
+ * @return Always PM_RET_OK
+ */
+PmReturn_t sli_ltoa16(int32_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase);
+
+/**
+ * Formats a pointer as a hexadecimal value.
+ *
+ * @param value the pointer
+ * @param buf a pointer to where the formatted string goes
+ * @param buflen the length of the given buffer in bytes
+ * @param upperCase when zero, hex chars rendered lowercase, else uppercase
+ * @return Always PM_RET_OK
+ */
+PmReturn_t sli_ptoa16(intptr_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase);
+
+/**
+ * Formats a 32-bit (single-precision) float as an ascii string.
+ *
+ * @param f the float value
+ * @param buf a pointer to where the formatted string goes
+ * @param buflen the size of the buffer
+ * @return Status
+ */
+PmReturn_t sli_ftoa(float f, uint8_t *buf, uint8_t buflen);
+
+#endif /* __SLI_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/strobj.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,599 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x12
+
+
+/**
+ * \file
+ * \brief String Object Type
+ *
+ * String object type opeartions.
+ */
+
+#include "pm.h"
+
+
+#if USE_STRING_CACHE
+/** String obj cachche: a list of all string objects. */
+static pPmString_t pstrcache = C_NULL;
+#endif /* USE_STRING_CACHE */
+
+
+/* The following 2 ascii values are used to escape printing to ipm */
+#define REPLY_TERMINATOR 0x04
+#define ESCAPE_CHAR 0x1B
+
+
+/*
+ * If USE_STRING_CACHE is defined nonzero, the string cache
+ * will be searched for an existing String object.
+ * If not found, a new object is created and inserted
+ * into the cache.
+ */
+PmReturn_t
+string_create(PmMemSpace_t memspace, uint8_t const **paddr, int16_t len,
+              int16_t n, pPmObj_t *r_pstring)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmString_t pstr = C_NULL;
+    uint8_t *pdst = C_NULL;
+    uint8_t const *psrc = C_NULL;
+
+#if USE_STRING_CACHE
+    pPmString_t pcacheentry = C_NULL;
+#endif /* USE_STRING_CACHE */
+    uint8_t *pchunk;
+
+    /* If loading from an image, get length from the image */
+    if (len < 0)
+    {
+        len = mem_getWord(memspace, paddr);
+    }
+
+    /* If loading from a C string, get its strlen (first null) */
+    else if (len == 0)
+    {
+        len = sli_strlen((char const *)*paddr);
+    }
+
+    /* Get space for String obj */
+    retval = heap_getChunk(sizeof(PmString_t) + len * n, &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pstr = (pPmString_t)pchunk;
+
+    /* Fill the string obj */
+    OBJ_SET_TYPE(pstr, OBJ_TYPE_STR);
+    pstr->length = len * n;
+
+    /* Copy C-string into String obj */
+    pdst = (uint8_t *)&(pstr->val);
+    while (--n >= 0)
+    {
+        psrc = *paddr;
+        mem_copy(memspace, &pdst, &psrc, len);
+    }
+
+    /* Be sure paddr points to one byte past the end of the source string */
+    *paddr = psrc;
+
+    /* Zero-pad end of string */
+    for (; pdst < (uint8_t *)pstr + PM_OBJ_GET_SIZE(pstr); pdst++)
+    {
+        *pdst = 0;
+    }
+
+#if USE_STRING_CACHE
+    /* Check for twin string in cache */
+    for (pcacheentry = pstrcache;
+         pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
+    {
+        /* If string already exists */
+        if (string_compare(pcacheentry, pstr) == C_SAME)
+        {
+            /* Free the string */
+            retval = heap_freeChunk((pPmObj_t)pstr);
+
+            /* Return ptr to old */
+            *r_pstring = (pPmObj_t)pcacheentry;
+            return retval;
+        }
+    }
+
+    /* Insert string obj into cache */
+    pstr->next = pstrcache;
+    pstrcache = pstr;
+
+#endif /* USE_STRING_CACHE */
+
+    *r_pstring = (pPmObj_t)pstr;
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+string_newFromChar(uint8_t const c, pPmObj_t *r_pstring)
+{
+    PmReturn_t retval;
+    uint8_t cstr[2];
+    uint8_t const *pcstr;
+
+    cstr[0] = c;
+    cstr[1] = '\0';
+    pcstr = cstr;
+
+    retval = string_new(&pcstr, r_pstring);
+
+    /* If c was a null character, force the length to 1 */
+    if (c == '\0')
+    {
+        ((pPmString_t)*r_pstring)->length = 1;
+    }
+
+    return retval;
+}
+
+
+int8_t
+string_compare(pPmString_t pstr1, pPmString_t pstr2)
+{
+    /* Return false if lengths are not equal */
+    if (pstr1->length != pstr2->length)
+    {
+        return C_DIFFER;
+    }
+
+    /* Compare the strings' contents */
+    return sli_strncmp((char const *)&(pstr1->val),
+                       (char const *)&(pstr2->val),
+                       pstr1->length) == 0 ? C_SAME : C_DIFFER;
+}
+
+
+#ifdef HAVE_PRINT
+PmReturn_t
+string_printFormattedBytes(uint8_t *pb, uint8_t is_escaped, uint16_t n)
+{
+    uint16_t i;
+    uint8_t ch;
+    uint8_t nibble;
+    PmReturn_t retval = PM_RET_OK;
+
+    if (is_escaped)
+    {
+        retval = plat_putByte('\'');
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    for (i = 0; i < n; i++)
+    {
+        ch = pb[i];
+        if (is_escaped && (ch == '\\'))
+        {
+            /* Output an additional backslash to escape it. */
+            retval = plat_putByte('\\');
+            PM_RETURN_IF_ERROR(retval);
+        }
+
+        /* Print the hex escape code of non-printable characters */
+        if (is_escaped
+            && ((ch < (uint8_t)32) || (ch >= (uint8_t)128) || (ch == '\'')))
+        {
+            plat_putByte('\\');
+            plat_putByte('x');
+
+            nibble = (ch >> (uint8_t)4) + '0';
+            if (nibble > '9')
+                nibble += ('a' - '0' - (uint8_t)10);
+            plat_putByte(nibble);
+
+            nibble = (ch & (uint8_t)0x0F) + '0';
+            if (nibble > '9')
+                nibble += ('a' - '0' - (uint8_t)10);
+            plat_putByte(nibble);
+        }
+        else
+        {
+            /* Escape the escape and reply terminator chars */
+            if ((ch == ESCAPE_CHAR) || (ch == REPLY_TERMINATOR))
+            {
+                plat_putByte(ESCAPE_CHAR);
+            }
+
+            /* Output character */
+            retval = plat_putByte(ch);
+            PM_RETURN_IF_ERROR(retval);
+        }
+    }
+    if (is_escaped)
+    {
+        retval = plat_putByte('\'');
+    }
+
+    return retval;
+}
+
+
+PmReturn_t
+string_print(pPmObj_t pstr, uint8_t is_escaped)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(pstr != C_NULL);
+
+    /* Ensure string obj */
+    if (OBJ_GET_TYPE(pstr) != OBJ_TYPE_STR)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    retval = string_printFormattedBytes(&(((pPmString_t)pstr)->val[0]),
+                                        is_escaped,
+                                        ((pPmString_t)pstr)->length);
+
+    return retval;
+}
+#endif /* HAVE_PRINT */
+
+
+PmReturn_t
+string_cacheInit(void)
+{
+    pstrcache = C_NULL;
+
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+string_getCache(pPmString_t **r_ppstrcache)
+{
+#if USE_STRING_CACHE
+    *r_ppstrcache = &pstrcache;
+#else
+    *r_ppstrcache = C_NULL;
+#endif
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+string_concat(pPmString_t pstr1, pPmString_t pstr2, pPmObj_t *r_pstring)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmString_t pstr = C_NULL;
+    uint8_t *pdst = C_NULL;
+    uint8_t const *psrc = C_NULL;
+#if USE_STRING_CACHE
+    pPmString_t pcacheentry = C_NULL;
+#endif /* USE_STRING_CACHE */
+    uint8_t *pchunk;
+    uint16_t len;
+
+    /* Create the String obj */
+    len = pstr1->length + pstr2->length;
+    retval = heap_getChunk(sizeof(PmString_t) + len, &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pstr = (pPmString_t)pchunk;
+    OBJ_SET_TYPE(pstr, OBJ_TYPE_STR);
+    pstr->length = len;
+
+    /* Concatenate C-strings into String obj and apply null terminator */
+    pdst = (uint8_t *)&(pstr->val);
+    psrc = (uint8_t const *)&(pstr1->val);
+    mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr1->length);
+    psrc = (uint8_t const *)&(pstr2->val);
+    mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr2->length);
+    *pdst = '\0';
+
+#if USE_STRING_CACHE
+    /* Check for twin string in cache */
+    for (pcacheentry = pstrcache;
+         pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
+    {
+        /* If string already exists */
+        if (string_compare(pcacheentry, pstr) == C_SAME)
+        {
+            /* Free the string */
+            retval = heap_freeChunk((pPmObj_t)pstr);
+
+            /* Return ptr to old */
+            *r_pstring = (pPmObj_t)pcacheentry;
+            return retval;
+        }
+    }
+
+    /* Insert string obj into cache */
+    pstr->next = pstrcache;
+    pstrcache = pstr;
+#endif /* USE_STRING_CACHE */
+
+    *r_pstring = (pPmObj_t)pstr;
+    return PM_RET_OK;
+}
+
+
+#ifdef HAVE_STRING_FORMAT
+
+#define SIZEOF_FMTDBUF 42
+#define SIZEOF_SMALLFMT 8
+
+PmReturn_t
+string_format(pPmString_t pstr, pPmObj_t parg, pPmObj_t *r_pstring)
+{
+    PmReturn_t retval;
+    uint16_t strsize = 0;
+    uint16_t strindex;
+    uint8_t *fmtcstr;
+    uint8_t smallfmtcstr[SIZEOF_SMALLFMT];
+    uint8_t fmtdbuf[SIZEOF_FMTDBUF];
+    uint8_t i;
+    uint8_t j;
+    uint8_t argtupleindex = 0;
+    pPmObj_t pobj;
+    int fmtretval;
+    uint8_t expectedargcount = 0;
+    pPmString_t pnewstr;
+    uint8_t *pchunk;
+#if USE_STRING_CACHE
+    pPmString_t pcacheentry = C_NULL;
+#endif /* USE_STRING_CACHE */
+
+    /* Get the first arg */
+    pobj = parg;
+
+    /* Calculate the size of the resulting string */
+    fmtcstr = pstr->val;
+    for (i = 0; i < pstr->length; i++)
+    {
+        /* Count non-format chars */
+        if (fmtcstr[i] != '%') { strsize++; continue; }
+
+        /* If double percents, count one percent */
+        if (fmtcstr[++i] == '%') { strsize++; continue; }
+
+        /* Get arg from the tuple */
+        if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
+        {
+            pobj = ((pPmTuple_t)parg)->val[argtupleindex++];
+        }
+
+        fmtretval = -1;
+
+        /* Format one arg to get its length */
+        smallfmtcstr[0] = '%';
+        for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++)
+        {
+            smallfmtcstr[j] = fmtcstr[i];
+            j++;
+
+            if ((fmtcstr[i] == 'd')
+                || (fmtcstr[i] == 'x')
+                || (fmtcstr[i] == 'X'))
+            {
+                if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    return retval;
+                }
+                smallfmtcstr[j] = '\0';
+#ifdef HAVE_SNPRINTF_FORMAT
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmInt_t)pobj)->val);
+#else
+                if (fmtcstr[i] == 'd')
+                {
+                    retval = sli_ltoa10(((pPmInt_t)pobj)->val,
+                                        fmtdbuf,
+                                        sizeof(fmtdbuf));
+                    PM_RETURN_IF_ERROR(retval);
+                }
+                else
+                {
+                    sli_ltoa16(((pPmInt_t)pobj)->val,
+                               fmtdbuf,
+                               sizeof(fmtdbuf),
+                               fmtcstr[i] == 'X');
+                }
+                fmtretval = sli_strlen((char *)fmtdbuf);
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+
+#ifdef HAVE_FLOAT
+            else if ((fmtcstr[i] == 'f') || (fmtcstr[i] == 'F'))
+            {
+                if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_FLT)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    return retval;
+                }
+#ifdef HAVE_SNPRINTF_FORMAT
+                smallfmtcstr[j] = '\0';
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val);
+#else
+                sli_ftoa(((pPmFloat_t)pobj)->val, fmtdbuf, SIZEOF_FMTDBUF);
+                fmtretval = sli_strlen((char *)fmtdbuf);
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+#endif /* HAVE_FLOAT */
+
+            else if (fmtcstr[i] == 's')
+            {
+                if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_STR)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    return retval;
+                }
+
+                /* Skip using snprintf(), just use length of string arg */
+                fmtretval = ((pPmString_t)pobj)->length;
+                break;
+            }
+        }
+
+        /* Raise ValueError if the format string was bad */
+        if (fmtretval < 0)
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+
+        expectedargcount++;
+        strsize += fmtretval;
+    }
+
+    /* TypeError wrong number args */
+    if (((OBJ_GET_TYPE(parg) != OBJ_TYPE_TUP) && (expectedargcount != 1))
+        || ((OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
+            && (expectedargcount != ((pPmTuple_t)parg)->length)))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Allocate and initialize String obj */
+    retval = heap_getChunk(sizeof(PmString_t) + strsize, &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pnewstr = (pPmString_t)pchunk;
+    OBJ_SET_TYPE(pnewstr, OBJ_TYPE_STR);
+    pnewstr->length = strsize;
+
+    /* Fill contents of String obj */
+    strindex = 0;
+    argtupleindex = 0;
+    pobj = parg;
+
+    for (i = 0; i < pstr->length; i++)
+    {
+        /* Copy non-format chars */
+        if (fmtcstr[i] != '%')
+        {
+            pnewstr->val[strindex++] = fmtcstr[i];
+            continue;
+        }
+
+        /* If double percents, copy one percent */
+        if (fmtcstr[++i] == '%')
+        {
+            pnewstr->val[strindex++] = '%';
+            continue;
+        }
+
+        /* Get arg from the tuple */
+        if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
+        {
+            pobj = ((pPmTuple_t)parg)->val[argtupleindex++];
+        }
+
+        fmtretval = -1;
+
+        /* Format one arg to get its length */
+        smallfmtcstr[0] = '%';
+        for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++)
+        {
+            smallfmtcstr[j] = fmtcstr[i];
+            j++;
+
+            if ((fmtcstr[i] == 'd')
+                || (fmtcstr[i] == 'x')
+                || (fmtcstr[i] == 'X'))
+            {
+                smallfmtcstr[j] = '\0';
+#ifdef HAVE_SNPRINTF_FORMAT
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmInt_t)pobj)->val);
+#else
+                if (fmtcstr[i] == 'd')
+                {
+                    retval = sli_ltoa10(((pPmInt_t)pobj)->val,
+                                        fmtdbuf,
+                                        sizeof(fmtdbuf));
+                    PM_RETURN_IF_ERROR(retval);
+                }
+                else
+                {
+                    sli_ltoa16(((pPmInt_t)pobj)->val,
+                               fmtdbuf,
+                               sizeof(fmtdbuf),
+                               fmtcstr[i] == 'X');
+                }
+                fmtretval = sli_strlen((char *)fmtdbuf);
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+
+#ifdef HAVE_FLOAT
+            else if ((fmtcstr[i] == 'f') || (fmtcstr[i] == 'F'))
+            {
+#ifdef HAVE_SNPRINTF_FORMAT
+                smallfmtcstr[j] = '\0';
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val);
+#else
+                sli_ftoa(((pPmFloat_t)pobj)->val, fmtdbuf, SIZEOF_FMTDBUF);
+                fmtretval = sli_strlen((char *)fmtdbuf);
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+#endif /* HAVE_FLOAT */
+
+            else if (fmtcstr[i] == 's')
+            {
+#ifdef HAVE_SNPRINTF_FORMAT
+                smallfmtcstr[j] = '\0';
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmString_t)pobj)->val);
+#else
+                sli_memcpy(fmtdbuf, ((pPmString_t)pobj)->val,
+                           ((pPmString_t)pobj)->length);
+                fmtretval = ((pPmString_t)pobj)->length;
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+        }
+
+        /* Copy formatted C string into new string object */
+        for (j = 0; j < fmtretval; j++)
+        {
+            pnewstr->val[strindex++] = fmtdbuf[j];
+        }
+    }
+    pnewstr->val[strindex] = '\0';
+
+#if USE_STRING_CACHE
+    /* Check for twin string in cache */
+    for (pcacheentry = pstrcache;
+         pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
+    {
+        /* If string already exists */
+        if (string_compare(pcacheentry, pnewstr) == C_SAME)
+        {
+            /* Free the string */
+            retval = heap_freeChunk((pPmObj_t)pnewstr);
+
+            /* Return ptr to old */
+            *r_pstring = (pPmObj_t)pcacheentry;
+            return retval;
+        }
+    }
+
+    /* Insert string obj into cache */
+    pnewstr->next = pstrcache;
+    pstrcache = pnewstr;
+
+#endif /* USE_STRING_CACHE */
+
+    *r_pstring = (pPmObj_t)pnewstr;
+    return PM_RET_OK;
+}
+#endif /* HAVE_STRING_FORMAT */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/strobj.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,215 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __STRING_H__
+#define __STRING_H__
+
+
+/**
+ * \file
+ * \brief String Object Type
+ *
+ * String object type header.
+ */
+
+
+/** Set to nonzero to enable string cache.  DO NOT REMOVE THE DEFINITION. */
+#define USE_STRING_CACHE 1
+
+
+/**
+ * Loads a string from image
+ *
+ * @param ms memoryspace paddr points to
+ * @param paddr address in memoryspace of source string
+ * @param r_pstring Return by reference; a new string object
+ * @return Return status
+ */
+#define string_loadFromImg(ms, paddr, r_pstring) \
+    string_create((ms), (paddr), (int16_t)-1, (int16_t)1, (r_pstring))
+
+/**
+ * Creates String object from character array in RAM
+ *
+ * @param paddr pointer to address of source string
+ * @param r_pstring Return arg; addr of ptr to string
+ */
+#define string_new(paddr, r_pstring) \
+    string_create(MEMSPACE_RAM, (uint8_t const **)(paddr), 0, (int16_t)1, (r_pstring))
+
+/**
+ * Creates String object from character array in RAM which may contain
+ * embedded null characters.
+ *
+ * @param paddr pointer to address of source string
+ * @param len length of source string
+ * @param r_pstring Return arg; addr of ptr to string
+ */
+#define string_newWithLen(paddr, len, r_pstring) \
+    string_create(MEMSPACE_RAM, (uint8_t const **)(paddr), (len), (int16_t)1, \
+                  (r_pstring))
+
+/**
+ * Creates String object by replicating an existing C string, n times
+ *
+ * @param paddr pointer to address of source string
+ * @param n number of times to replicate the source string
+ * @param r_pstring Return arg; addr of ptr to string
+ */
+#define string_replicate(paddr, n, r_pstring) \
+    string_create(MEMSPACE_RAM, (paddr), (uint8_t)0, (n), (r_pstring))
+
+/***************************************************************
+ * Types
+ **************************************************************/
+
+/**
+ * String obj
+ *
+ * Null terminated array of chars.
+ */
+typedef struct PmString_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Length of string */
+    uint16_t length;
+
+#if USE_STRING_CACHE
+    /** Ptr to next string in cache */
+    struct PmString_s *next;
+#endif                          /* USE_STRING_CACHE */
+
+    /**
+     * Null-term char array
+     *
+     * Use length 1 here so that string-alloc function can use
+     * "sizeof(PmString_t) + len" and there will be room for the null-term
+     */
+    uint8_t val[1];
+} PmString_t,
+ *pPmString_t;
+
+
+/***************************************************************
+ * Prototypes
+ **************************************************************/
+
+/**
+ * Creates a new String obj.
+ * If len is less than zero, load from a String image.
+ * If len is zero, copy from a C string (which has a null terminator)
+ * If len is positive, copy as many chars as given in the len argument
+ *      A string image has the following structure:
+ *          -type:      int8 - OBJ_TYPE_STRING
+ *          -length:    uint16 - number of bytes in the string
+ *          -val:       uint8[] - array of chars with null term
+ *
+ * Returns by reference a ptr to String obj.
+ *
+ * Obtain space for String from the heap.
+ * Copy string from memspace.
+ * Leave contents of paddr pointing one byte past end of str.
+ *
+ * THE PROGRAMMER SHOULD NOT CALL THIS FUNCTION DIRECTLY.
+ * Instead, use one of the two macros string_loadFromImg()
+ * or string_new().
+ *
+ * @param   memspace memory space where *paddr points
+ * @param   paddr ptr to ptr to null term character array or image.
+ * @param   len length of the C character array
+ *          (use -1 for string images, 0 for C strings)
+ * @param   n Number of times to replicate the given string argument
+ * @param   r_pstring Return by reference; ptr to String obj
+ * @return  Return status
+ */
+PmReturn_t string_create(PmMemSpace_t memspace, uint8_t const **paddr,
+                         int16_t len, int16_t n, pPmObj_t *r_pstring);
+
+/**
+ * Creates a new String object from a single character.
+ *
+ * @param   c The character to become the string
+ * @param   r_pstring Return by reference; ptr to String obj
+ * @return  Return status
+ */
+PmReturn_t string_newFromChar(uint8_t const c, pPmObj_t *r_pstring);
+
+/**
+ * Compares two String objects for equality.
+ *
+ * @param   pstr1 Ptr to first string
+ * @param   pstr2 Ptr to second string
+ * @return  C_SAME if the strings are equivalent, C_DIFFER otherwise
+ */
+int8_t string_compare(pPmString_t pstr1, pPmString_t pstr2);
+
+#ifdef HAVE_PRINT
+/**
+ * Sends out a string object bytewise. Escaping and framing is configurable
+ * via is_escaped.
+ *
+ * @param pstr Ptr to string object
+ * @param is_escaped If 0, print out string as is. Otherwise escape unprintable
+ *                   characters and surround string with single quotes.
+ * @return Return status
+ */
+PmReturn_t string_print(pPmObj_t pstr, uint8_t is_escaped);
+#endif /* HAVE_PRINT */
+
+/**
+ * Clears the string cache if one exists.
+ * Called by heap_init()
+ *
+ * @return Return status
+ */
+PmReturn_t string_cacheInit(void);
+
+
+/** Returns a pointer to the base of the string cache */
+PmReturn_t string_getCache(pPmString_t **r_ppstrcache);
+
+/**
+ * Returns a new string object that is the concatenation
+ * of the two given strings.
+ *
+ * @param pstr1 First source string
+ * @param pstr2 Second source string
+ * @param r_pstring Return arg; ptr to new string object
+ * @return Return status
+ */
+PmReturn_t
+string_concat(pPmString_t pstr1, pPmString_t pstr2, pPmObj_t *r_pstring);
+
+/**
+ * Returns a new string object that is created from the given format string
+ * and the argument(s).
+ *
+ * @param pstr Format string object
+ * @param parg Single argument or tuple of arguments
+ * @param r_pstring Return arg; ptr to new string object
+ * @return Return status
+ */
+PmReturn_t string_format(pPmString_t pstr, pPmObj_t parg, pPmObj_t *r_pstring);
+
+#ifdef HAVE_PRINT
+/**
+ * Prints n bytes, formatting them if is_escaped is true
+ *
+ * @param pb Pointer to C bytes
+ * @param is_escaped Boolean true if string is to be escaped
+ * @param n Number of bytes to print
+ * @return Return status
+ */
+PmReturn_t string_printFormattedBytes(uint8_t *pb,
+                                      uint8_t is_escaped,
+                                      uint16_t n);
+#endif /* HAVE_PRINT */
+
+#endif /* __STRING_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/thread.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,50 @@
+/*
+# This file is Copyright 2007 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x16
+
+
+/**
+ * \file
+ * \brief VM Thread
+ *
+ * Encapsulating a frame pointer, a root code object and thread state.
+ */
+
+
+#include "pm.h"
+
+
+PmReturn_t
+thread_new(pPmObj_t pframe, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmThread_t pthread = C_NULL;
+
+    C_ASSERT(pframe != C_NULL);
+
+    /* If it's not a frame, raise TypeError */
+    if (OBJ_GET_TYPE(pframe) != OBJ_TYPE_FRM)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Allocate a thread */
+    retval = heap_getChunk(sizeof(PmThread_t), (uint8_t **)r_pobj);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Set type, frame and initialize status */
+    pthread = (pPmThread_t)*r_pobj;
+    OBJ_SET_TYPE(pthread, OBJ_TYPE_THR);
+    pthread->pframe = (pPmFrame_t)pframe;
+    pthread->interpctrl = INTERP_CTRL_CONT;
+
+    return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/thread.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,81 @@
+/*
+# This file is Copyright 2007 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __THREAD_H__
+#define __THREAD_H__
+
+
+/**
+ * \file
+ * \brief VM Thread
+ *
+ * Encapsulating a frame pointer, a root code object and thread state.
+ */
+
+
+#include "interp.h"
+
+
+ /** Frequency in Hz to switch threads */
+#define THREAD_RESCHEDULE_FREQUENCY    10
+
+
+/**
+ * Interpreter return values
+ *
+ * Used to control interpreter loop
+ * and indicate return value.
+ * Negative values indicate erroneous results.
+ * Positive values indicate "continue interpreting",
+ * but first do something special like reschedule threads
+ * or (TBD) sweep the heap.
+ */
+typedef enum PmInterpCtrl_e
+{
+    /* other erroneous exits go here with negative values */
+    INTERP_CTRL_ERR = -1,   /**< Generic error causes exit */
+    INTERP_CTRL_EXIT = 0,   /**< Normal execution exit */
+    INTERP_CTRL_CONT = 1,   /**< Continue interpreting */
+    INTERP_CTRL_RESCHED = 2 /**< Reschedule threads */
+        /* all positive values indicate "continue interpreting" */
+} PmInterpCtrl_t, *pPmInterpCtrl_t;
+
+/**
+ * Thread obj
+ *
+ */
+typedef struct PmThread_s
+{
+    /** object descriptor */
+    PmObjDesc_t od;
+
+    /** current frame pointer */
+    pPmFrame_t pframe;
+
+    /**
+     * Interpreter loop control value
+     *
+     * A positive value means continue interpreting.
+     * A zero value means normal interpreter exit.
+     * A negative value signals an error exit.
+     */
+    PmInterpCtrl_t interpctrl;
+} PmThread_t,
+ *pPmThread_t;
+
+
+/**
+ * Constructs a thread for a root frame.
+ *
+ * @param pframe Frame object as a basis for this thread.
+ * @param r_pobj Return by reference; Ptr to the newly created thread object.
+ * @return Return status
+ */
+PmReturn_t thread_new(pPmObj_t pframe, pPmObj_t *r_pobj);
+
+#endif /* __THREAD_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/tuple.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,194 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x13
+
+
+/**
+ * \file
+ * \brief Tuple Object Type
+ *
+ * Tuple object type operations.
+ */
+
+
+#include "pm.h"
+
+
+/* The follwing value should match that in pmImgCreator.py */
+#define MAX_TUPLE_LEN 253
+
+
+PmReturn_t
+tuple_loadFromImg(PmMemSpace_t memspace,
+                  uint8_t const **paddr, pPmObj_t *r_ptuple)
+{
+    PmReturn_t retval = PM_RET_OK;
+    uint8_t i = (uint8_t)0;
+    uint8_t n = (uint8_t)0;
+    uint8_t objid;
+
+    /* Get num objs in tuple */
+    n = mem_getByte(memspace, paddr);
+
+    /* Create empty tuple */
+    retval = tuple_new(n, r_ptuple);
+    PM_RETURN_IF_ERROR(retval);
+    ((pPmTuple_t)*r_ptuple)->length = 0;
+
+    /* Load the next n objs into tuple */
+    heap_gcPushTempRoot((pPmObj_t)*r_ptuple, &objid);
+    for (i = (uint8_t)0; i < n; i++)
+    {
+        retval = obj_loadFromImg(memspace,
+                                 paddr,
+                                 (pPmObj_t *)&(((pPmTuple_t)*r_ptuple)->
+                                               val[i]));
+        if (retval != PM_RET_OK)
+        {
+            heap_gcPopTempRoot(objid);
+            return retval;
+        }
+        ((pPmTuple_t)*r_ptuple)->length++;
+    }
+    heap_gcPopTempRoot(objid);
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+tuple_new(uint16_t n, pPmObj_t *r_ptuple)
+{
+    PmReturn_t retval = PM_RET_OK;
+    uint16_t size = 0;
+
+    /* Raise a SystemError for a Tuple that is too large */
+    if (n > MAX_TUPLE_LEN)
+    {
+        PM_RAISE(retval, PM_RET_EX_SYS);
+        return retval;
+    }
+
+    /* Calc size of struct to hold tuple; (n-1) because PmTuple_t has val[1] */
+    size = sizeof(PmTuple_t) + ((n - 1) * sizeof(pPmObj_t));
+
+    /* Allocate a tuple */
+    retval = heap_getChunk(size, (uint8_t **)r_ptuple);
+    PM_RETURN_IF_ERROR(retval);
+    OBJ_SET_TYPE(*r_ptuple, OBJ_TYPE_TUP);
+
+    /* Set the number of objs in the tuple */
+    ((pPmTuple_t)*r_ptuple)->length = n;
+
+    /* Clear entries in the tuple so the GC doesn't try to mark/sweep them */
+    if (n > 0)
+    {
+        size = n;
+        while (--size > 0)
+        {
+            ((pPmTuple_t)*r_ptuple)->val[size] = C_NULL;
+        }
+    }
+
+    /* No need to null the ptrs because they are set by the caller */
+    return retval;
+}
+
+
+PmReturn_t
+tuple_replicate(pPmObj_t ptup, int16_t n, pPmObj_t *r_ptuple)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t length;
+    int16_t i;
+    int16_t j;
+
+    /* Raise TypeError if object is not a Tuple */
+    if (OBJ_GET_TYPE(ptup) != OBJ_TYPE_TUP)
+    {
+        PM_RAISE(retval, PM_RET_EX_SYS);
+        return retval;
+    }
+
+    C_ASSERT(n >= 0);
+
+    /* Allocate the new tuple */
+    length = ((pPmTuple_t)ptup)->length;
+    retval = tuple_new(length * n, r_ptuple);
+    PM_RETURN_IF_ERROR(retval);
+
+    /* Copy src tuple the designated number of times */
+    for (i = 0; i < n; i++)
+    {
+        for (j = 0; j < length; j++)
+        {
+            ((pPmTuple_t)*r_ptuple)->val[length * i + j] =
+                ((pPmTuple_t)ptup)->val[j];
+        }
+    }
+    return retval;
+}
+
+
+PmReturn_t
+tuple_getItem(pPmObj_t ptup, int16_t index, pPmObj_t *r_pobj)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Adjust for negative index */
+    if (index < 0)
+    {
+        index += ((pPmTuple_t)ptup)->length;
+    }
+
+    /* Raise IndexError if index is out of bounds */
+    if ((index < 0) || (index > ((pPmTuple_t)ptup)->length))
+    {
+        PM_RAISE(retval, PM_RET_EX_INDX);
+    }
+
+    /* Get the tuple item */
+    *r_pobj = ((pPmTuple_t)ptup)->val[index];
+
+    return retval;
+}
+
+
+#ifdef HAVE_PRINT
+PmReturn_t
+tuple_print(pPmObj_t ptup)
+{
+    PmReturn_t retval = PM_RET_OK;
+    int16_t index;
+
+    C_ASSERT(ptup != C_NULL);
+
+    /* If it's not a tuple, raise TypeError */
+    if (OBJ_GET_TYPE(ptup) != OBJ_TYPE_TUP)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    plat_putByte('(');
+
+    for (index = 0; index < ((pPmTuple_t)ptup)->length; index++)
+    {
+        if (index != 0)
+        {
+            plat_putByte(',');
+            plat_putByte(' ');
+        }
+        retval = obj_print(((pPmTuple_t)ptup)->val[index], C_FALSE, C_TRUE);
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    return plat_putByte(')');
+}
+#endif /* HAVE_PRINT */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/tuple.h	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,109 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#ifndef __TUPLE_H__
+#define __TUPLE_H__
+
+
+/**
+ * \file
+ * \brief Tuple Object Type
+ *
+ * Tuple object type header.
+ */
+
+/**
+ * Tuple obj
+ *
+ * Immutable ordered sequence.  Contains array of ptrs to objs.
+ */
+typedef struct PmTuple_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /**
+     * Length of tuple
+     * I don't expect a tuple to ever exceed 255 elements,
+     * but if I set this type to int8_t, a 0-element tuple
+     * is too small to be allocated.
+     */
+    uint16_t length;
+
+    /** Array of ptrs to objs */
+    pPmObj_t val[1];
+} PmTuple_t,
+ *pPmTuple_t;
+
+
+#define tuple_copy(src, dest) tuple_replicate((src), 1, (dest))
+
+
+/**
+ * Creates a Tuple by loading a tuple image from memory.
+ *
+ * Obtain space for tuple from the heap.
+ * Load all objs within the tuple img.
+ * Leave contents of paddr pointing one byte past end of
+ * last obj in tuple.
+ *
+ * The tuple image has the following structure:
+ *      -type:      S8 - OBJ_TYPE_TUPLE
+ *      -length     U8 - N number of objects in the tuple.
+ *                  N objects follow in the stream.
+ *
+ * @param   memspace Memory space.
+ * @param   paddr Ptr to ptr to tuple in memspace
+ * @param   r_ptuple Return by reference; new filled tuple
+ * @return  Return status
+ */
+PmReturn_t tuple_loadFromImg(PmMemSpace_t memspace,
+                             uint8_t const **paddr, pPmObj_t *r_ptuple);
+
+/**
+ * Allocates space for a new Tuple.  Returns a pointer to the tuple.
+ *
+ * @param   n the number of elements the tuple will contain
+ * @param   r_ptuple Return by ref, ptr to new tuple
+ * @return  Return status
+ */
+PmReturn_t tuple_new(uint16_t n, pPmObj_t *r_ptuple);
+
+/**
+ * Replicates a tuple, n number of times to create a new tuple
+ *
+ * Copies the pointers (not the objects).
+ *
+ * @param   ptup Ptr to source tuple.
+ * @param   n Number of times to replicate the tuple.
+ * @param   r_ptuple Return arg; Ptr to new tuple.
+ * @return  Return status
+ */
+PmReturn_t tuple_replicate(pPmObj_t ptup, int16_t n, pPmObj_t *r_ptuple);
+
+/**
+ * Gets the object in the tuple at the index.
+ *
+ * @param   ptup Ptr to tuple obj
+ * @param   index Index into tuple
+ * @param   r_pobj Return by reference; ptr to item
+ * @return  Return status
+ */
+PmReturn_t tuple_getItem(pPmObj_t ptup, int16_t index, pPmObj_t *r_pobj);
+
+#ifdef HAVE_PRINT
+/**
+ * Prints out a tuple. Uses obj_print() to print elements.
+ *
+ * @param pobj Object to print.
+ * @return Return status
+ */
+PmReturn_t tuple_print(pPmObj_t pobj);
+#endif /* HAVE_PRINT */
+
+#endif /* __TUPLE_H__ */