diff --git a/py/.gitignore b/py/.gitignore
deleted file mode 100644
index e7f3545dc6e7ea8e0e771565e25bce77599b8cd6..0000000000000000000000000000000000000000
--- a/py/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-*.o
-py
-*.py
-.*.swp
diff --git a/py/Makefile b/py/Makefile
deleted file mode 100644
index 0f4483d6a26a8374af432ed2164bebc5fb9caa45..0000000000000000000000000000000000000000
--- a/py/Makefile
+++ /dev/null
@@ -1,52 +0,0 @@
-CC = gcc
-CFLAGS = -Wall -ansi -std=gnu99 -Os -DEMIT_ENABLE_CPY -DEMIT_ENABLE_THUMB #-DNDEBUG
-LDFLAGS =
-
-SRC = \
-	malloc.c \
-	misc.c \
-	qstr.c \
-	lexer.c \
-	lexerfile.c \
-	parse.c \
-	scope.c \
-	compile.c \
-	emitcommon.c \
-	emitpass1.c \
-	emitcpy.c \
-	emitbc.c \
-	asmx64.c \
-	asmthumb.c \
-	emitinlinethumb.c \
-	runtime.c \
-	vm.c \
-	main.c \
-
-SRC_ASM = \
-
-OBJ = $(SRC:.c=.o) $(SRC_ASM:.s=.o) emitnx64.o emitnthumb.o
-LIB =
-PROG = py
-
-$(PROG): $(OBJ)
-	$(CC) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
-
-runtime.o: runtime.c
-	$(CC) $(CFLAGS) -O3 -c -o $@ $<
-
-vm.o: vm.c
-	$(CC) $(CFLAGS) -O3 -c -o $@ $<
-
-parse.o: grammar.h
-compile.o: grammar.h
-emitcpy.o: emit.h
-emitbc.o: emit.h
-
-emitnx64.o: emitnative.c emit.h
-	$(CC) $(CFLAGS) -DN_X64 -c -o $@ $<
-
-emitnthumb.o: emitnative.c emit.h
-	$(CC) $(CFLAGS) -DN_THUMB -c -o $@ $<
-
-clean:
-	/bin/rm $(OBJ)
diff --git a/py/asmthumb.c b/py/asmthumb.c
index ba61c31f65fb16c3d9e05004bdf5b39f5d36db0d..a6b95764ba1ed1def54a5559700d5703261af56e 100644
--- a/py/asmthumb.c
+++ b/py/asmthumb.c
@@ -4,7 +4,7 @@
 #include <string.h>
 
 #include "misc.h"
-#include "machine.h"
+#include "mpyconfig.h"
 #include "asmthumb.h"
 
 #define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0)
diff --git a/py/compile.c b/py/compile.c
index 3d5a29a192086b29adf7e59f0f8805b130955ec9..810446189d58f09cd222b0bf28e4414612bc4146 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -6,8 +6,8 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "scope.h"
 #include "compile.h"
@@ -768,8 +768,10 @@ static bool compile_built_in_decorator(compiler_t *comp, int name_len, py_parse_
         *emit_options = EMIT_OPT_NATIVE_PYTHON;
     } else if (attr == comp->qstr_viper) {
         *emit_options = EMIT_OPT_VIPER;
+#if defined(MICROPY_EMIT_ENABLE_INLINE_THUMB)
     } else if (attr == comp->qstr_asm_thumb) {
         *emit_options = EMIT_OPT_ASM_THUMB;
+#endif
     } else {
         printf("SyntaxError: invalid micropython decorator\n");
     }
@@ -2673,8 +2675,11 @@ void py_compile(py_parse_node_t pn) {
     comp->emit_inline_asm_method_table = NULL;
     uint max_num_labels = 0;
     for (scope_t *s = comp->scope_head; s != NULL; s = s->next) {
-        if (s->emit_options == EMIT_OPT_ASM_THUMB) {
+        if (false) {
+#ifdef MICROPY_EMIT_ENABLE_INLINE_THUMB
+        } else if (s->emit_options == EMIT_OPT_ASM_THUMB) {
             compile_scope_inline_asm(comp, s, PASS_1);
+#endif
         } else {
             compile_scope(comp, s, PASS_1);
         }
@@ -2694,11 +2699,20 @@ void py_compile(py_parse_node_t pn) {
     emit_pass1_free(comp->emit);
 
     // compile pass 2 and 3
+#if !defined(MICROPY_EMIT_ENABLE_CPYTHON)
     emit_t *emit_bc = NULL;
     emit_t *emit_native = NULL;
+#endif
+#if defined(MICROPY_EMIT_ENABLE_INLINE_THUMB)
     emit_inline_asm_t *emit_inline_thumb = NULL;
+#endif
     for (scope_t *s = comp->scope_head; s != NULL; s = s->next) {
-        if (s->emit_options == EMIT_OPT_ASM_THUMB) {
+        if (false) {
+            // dummy
+
+#if defined(MICROPY_EMIT_ENABLE_INLINE_THUMB)
+        } else if (s->emit_options == EMIT_OPT_ASM_THUMB) {
+            // inline assembly for thumb
             if (emit_inline_thumb == NULL) {
                 emit_inline_thumb = emit_inline_thumb_new(max_num_labels);
             }
@@ -2708,15 +2722,31 @@ void py_compile(py_parse_node_t pn) {
             comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
             compile_scope_inline_asm(comp, s, PASS_2);
             compile_scope_inline_asm(comp, s, PASS_3);
+#endif
+
         } else {
+
+            // choose the emit type
+
+#if defined(MICROPY_EMIT_ENABLE_CPYTHON)
+            comp->emit = emit_cpython_new(max_num_labels);
+            comp->emit_method_table = &emit_cpython_method_table;
+#else
             switch (s->emit_options) {
                 case EMIT_OPT_NATIVE_PYTHON:
                 case EMIT_OPT_VIPER:
+#if defined(MICROPY_EMIT_ENABLE_X64)
                     if (emit_native == NULL) {
                         emit_native = emit_native_x64_new(max_num_labels);
                     }
-                    comp->emit = emit_native;
                     comp->emit_method_table = &emit_native_x64_method_table;
+#elif defined(MICROPY_EMIT_ENABLE_THUMB)
+                    if (emit_native == NULL) {
+                        emit_native = emit_native_thumb_new(max_num_labels);
+                    }
+                    comp->emit_method_table = &emit_native_thumb_method_table;
+#endif
+                    comp->emit = emit_native;
                     comp->emit_method_table->set_native_types(comp->emit, s->emit_options == EMIT_OPT_VIPER);
                     break;
 
@@ -2728,8 +2758,9 @@ void py_compile(py_parse_node_t pn) {
                     comp->emit_method_table = &emit_bc_method_table;
                     break;
             }
-            //comp->emit = emit_cpython_new(max_num_labels);
-            //comp->emit_method_table = &emit_cpython_method_table;
+#endif
+
+            // compile pass 2 and pass 3
             compile_scope(comp, s, PASS_2);
             compile_scope(comp, s, PASS_3);
         }
diff --git a/py/emitbc.c b/py/emitbc.c
index f242828e621456e56c329ae534fd26253f09834e..8f28910c089afabf35242a41f65395a35e09927a 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -6,8 +6,8 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "compile.h"
 #include "scope.h"
diff --git a/py/emitcommon.c b/py/emitcommon.c
index 6d4c0714194897e04cdb4446ca9502d549c0e0e7..07eb1812fd86198efc08a5bc61044db99108b176 100644
--- a/py/emitcommon.c
+++ b/py/emitcommon.c
@@ -5,8 +5,8 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "scope.h"
 #include "runtime.h"
diff --git a/py/emitcpy.c b/py/emitcpy.c
index 7c9615c09a45d601a2b1d8e6c41813ce64d56561..596e04eb822ea0a5e403dcd21ae447e940d84bfa 100644
--- a/py/emitcpy.c
+++ b/py/emitcpy.c
@@ -6,15 +6,15 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "compile.h"
 #include "scope.h"
 #include "runtime.h"
 #include "emit.h"
 
-#ifdef EMIT_ENABLE_CPY
+#ifdef MICROPY_EMIT_ENABLE_CPYTHON
 
 struct _emit_t {
     int pass;
@@ -925,4 +925,4 @@ const emit_method_table_t emit_cpython_method_table = {
     emit_cpy_yield_from,
 };
 
-#endif // EMIT_ENABLE_CPY
+#endif // MICROPY_EMIT_ENABLE_CPYTHON
diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c
index ae226b74e74d59bea0c4e359cd6159de9a403aa9..74bc6d129f95161f37a604112ea339204635946f 100644
--- a/py/emitinlinethumb.c
+++ b/py/emitinlinethumb.c
@@ -6,15 +6,15 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "scope.h"
 #include "runtime.h"
 #include "emit.h"
 #include "asmthumb.h"
 
-#ifdef EMIT_ENABLE_THUMB
+#ifdef MICROPY_EMIT_ENABLE_INLINE_THUMB
 
 struct _emit_inline_asm_t {
     int pass;
@@ -204,4 +204,4 @@ const emit_inline_asm_method_table_t emit_inline_thumb_method_table = {
     emit_inline_thumb_op,
 };
 
-#endif // EMIT_ENABLE_THUMB
+#endif // MICROPY_EMIT_ENABLE_INLINE_THUMB
diff --git a/py/emitnative.c b/py/emitnative.c
index db375181af89d1758de2a737d7817a77cd4eac37..0f09c079a0f868bbf7dec0d6027b8b33c53966b9 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -24,22 +24,13 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "scope.h"
 #include "runtime.h"
 #include "emit.h"
 
-// select a machine architecture
-#if 0
-#if defined(EMIT_ENABLE_NATIVE_X64)
-#define N_X64
-#elif defined(EMIT_ENABLE_NATIVE_THUMB)
-#define N_THUMB
-#endif
-#endif
-
 // wrapper around everything in this file
 #if defined(N_X64) || defined(N_THUMB)
 
diff --git a/py/emitpass1.c b/py/emitpass1.c
index 661a622bbcc4b27cac6cc9052e56207d1e93ca71..f14ccc5111a1cbc0a10aa9b848f8be3bbfd81759 100644
--- a/py/emitpass1.c
+++ b/py/emitpass1.c
@@ -6,8 +6,8 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "compile.h"
 #include "scope.h"
diff --git a/py/emitthumb.c b/py/emitthumb.c
index 7bcdf9e43de899232a8b2045e8a342b6d3ab58e5..1866e00b9a6221225cb563e56b83c9db8ea3a502 100644
--- a/py/emitthumb.c
+++ b/py/emitthumb.c
@@ -6,15 +6,15 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "scope.h"
 #include "runtime.h"
 #include "emit.h"
 #include "asmthumb.h"
 
-#ifdef EMIT_ENABLE_THUMB
+#ifdef MICROPY_EMIT_ENABLE_THUMB
 
 #define REG_LOCAL_1 (REG_R4)
 #define REG_LOCAL_2 (REG_R5)
@@ -775,4 +775,4 @@ const emit_method_table_t emit_thumb_method_table = {
     emit_thumb_yield_from,
 };
 
-#endif // EMIT_ENABLE_THUMB
+#endif // MICROPY_EMIT_ENABLE_THUMB
diff --git a/py/machine.h b/py/machine.h
deleted file mode 100644
index fa39c8f2d0c79f4dce6358841ad7420cb07bd545..0000000000000000000000000000000000000000
--- a/py/machine.h
+++ /dev/null
@@ -1,4 +0,0 @@
-typedef int64_t machine_int_t; // must be pointer size
-typedef uint64_t machine_uint_t; // must be pointer size
-typedef void *machine_ptr_t; // must be of pointer size
-typedef double machine_float_t;
diff --git a/py/parse.c b/py/parse.c
index 124d00ffebda3862f800452e28bb54656c5d3570..541c4eb3f549bf22f2193a11b81a7c0ac92f5966 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -7,8 +7,8 @@
 #include <assert.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 
 #define RULE_ACT_KIND_MASK      (0xf0)
diff --git a/py/runtime.c b/py/runtime.c
index 958507521fc2a566b8c48d3ffd8b9bc821863e2b..ae24646295e7401a49991b02a6ee4349031842fe 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -5,7 +5,7 @@
 #include <assert.h>
 
 #include "misc.h"
-#include "machine.h"
+#include "mpyconfig.h"
 #include "runtime.h"
 #include "bc.h"
 
@@ -19,9 +19,6 @@
 #define DEBUG_OP_printf(args...) (void)0
 #endif
 
-// enable/disable float support with this definition
-#define PY_FLOAT (1)
-
 typedef machine_int_t py_small_int_t;
 
 #define IS_O(o, k) (((((py_small_int_t)(o)) & 1) == 0) && (((py_obj_base_t*)(o))->kind == (k)))
@@ -29,14 +26,14 @@ typedef machine_int_t py_small_int_t;
 #define FROM_SMALL_INT(o) (((py_small_int_t)(o)) >> 1)
 #define TO_SMALL_INT(o) ((py_obj_t)(((o) << 1) | 1))
 
-#ifdef PY_FLOAT
+#ifdef MICROPY_ENABLE_FLOAT
 typedef machine_float_t float_t;
 #endif
 
 typedef enum {
     O_CONST,
     O_STR,
-#ifdef PY_FLOAT
+#ifdef MICROPY_ENABLE_FLOAT
     O_FLOAT,
 #endif
     O_FUN_0,
@@ -77,7 +74,7 @@ struct _py_obj_base_t {
     union {
         const char *id;
         qstr u_str;
-#ifdef PY_FLOAT
+#ifdef MICROPY_ENABLE_FLOAT
         float_t u_flt;
 #endif
         struct { // for O_FUN_[012N]
@@ -260,7 +257,7 @@ py_obj_t py_obj_new_str(qstr qstr) {
     return (py_obj_t)o;
 }
 
-#ifdef PY_FLOAT
+#ifdef MICROPY_ENABLE_FLOAT
 py_obj_t py_obj_new_float(float_t val) {
     py_obj_base_t *o = m_new(py_obj_base_t, 1);
     o->kind = O_FLOAT;
@@ -514,7 +511,7 @@ const char *py_obj_get_type_str(py_obj_t o_in) {
                 }
             case O_STR:
                 return "str";
-#ifdef PY_FLOAT
+#ifdef MICROPY_ENABLE_FLOAT
             case O_FLOAT:
                 return "float";
 #endif
@@ -557,7 +554,7 @@ void py_obj_print(py_obj_t o_in) {
                 // TODO need to escape chars etc
                 printf("'%s'", qstr_str(o->u_str));
                 break;
-#ifdef PY_FLOAT
+#ifdef MICROPY_ENABLE_FLOAT
             case O_FLOAT:
                 printf("%f", o->u_flt);
                 break;
@@ -719,7 +716,7 @@ py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs) {
             case RT_BINARY_OP_SUBTRACT: val = FROM_SMALL_INT(lhs) - FROM_SMALL_INT(rhs); break;
             case RT_BINARY_OP_MULTIPLY: val = FROM_SMALL_INT(lhs) * FROM_SMALL_INT(rhs); break;
             case RT_BINARY_OP_FLOOR_DIVIDE: val = FROM_SMALL_INT(lhs) / FROM_SMALL_INT(rhs); break;
-#ifdef PY_FLOAT
+#ifdef MICROPY_ENABLE_FLOAT
             case RT_BINARY_OP_TRUE_DIVIDE: return py_obj_new_float((float_t)FROM_SMALL_INT(lhs) / (float_t)FROM_SMALL_INT(rhs));
 #endif
             default: printf("%d\n", op); assert(0); val = 0;
@@ -864,9 +861,11 @@ machine_uint_t rt_convert_obj_for_inline_asm(py_obj_t obj) {
                 // pointer to the string (it's probably constant though!)
                 return (machine_uint_t)qstr_str(o->u_str);
 
+#ifdef MICROPY_ENABLE_FLOAT
             case O_FLOAT:
                 // convert float to int (could also pass in float registers)
                 return (machine_int_t)o->u_flt;
+#endif
 
             case O_LIST:
                 // pointer to start of list (could pass length, but then could use len(x) for that)
diff --git a/py/scope.c b/py/scope.c
index 640d4f742b989c1a7598b6cf2e21222a0ac40b43..c5816871c2eb65bac9cb55a6ae928afad97c53d7 100644
--- a/py/scope.c
+++ b/py/scope.c
@@ -4,7 +4,7 @@
 #include <assert.h>
 
 #include "misc.h"
-#include "machine.h"
+#include "mpyconfig.h"
 #include "parse.h"
 #include "scope.h"
 
diff --git a/py/vm.c b/py/vm.c
index e672ef799ec5a66af7ff42e6c2dfd55a79d82799..d6740cf04d5302fbc838ae276d560dcc9548ea7e 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -5,7 +5,7 @@
 #include <assert.h>
 
 #include "misc.h"
-#include "machine.h"
+#include "mpyconfig.h"
 #include "runtime.h"
 #include "bc.h"
 
diff --git a/unix/Makefile b/unix/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..6a48cee221fd1a2245249c8233036d36da8f6d83
--- /dev/null
+++ b/unix/Makefile
@@ -0,0 +1,65 @@
+PYSRC=../py
+BUILD=build
+
+CC = gcc
+CFLAGS = -I. -I$(PYSRC) -Wall -ansi -std=gnu99 -Os #-DNDEBUG
+CFLAGS_PY = -DEMIT_ENABLE_CPY -DEMIT_ENABLE_THUMB
+LDFLAGS =
+
+SRC_C = \
+	main.c \
+
+PY_O = \
+	malloc.o \
+	qstr.o \
+	misc.o \
+	lexer.o \
+	lexerfile.o \
+	parse.o \
+	scope.o \
+	compile.o \
+	emitcommon.o \
+	emitpass1.o \
+	emitcpy.o \
+	emitbc.o \
+	asmx64.o \
+	emitnx64.o \
+	asmthumb.o \
+	emitnthumb.o \
+	emitinlinethumb.o \
+	runtime.o \
+	vm.o \
+
+OBJ = $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(PY_O))
+LIB =
+PROG = py
+
+$(PROG): $(BUILD) $(OBJ)
+	$(CC) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
+
+$(BUILD):
+	mkdir $@
+
+$(BUILD)/%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+$(BUILD)/%.o: $(PYSRC)/%.c mpyconfig.h
+	$(CC) $(CFLAGS) $(CFLAGS_PY) -c -o $@ $<
+
+$(BUILD)/emitnx64.o: $(PYSRC)/emitnative.c $(PYSRC)/emit.h
+	$(CC) $(CFLAGS) $(CFLAGS_PY) -DN_X64 -c -o $@ $<
+
+$(BUILD)/emitnthumb.o: $(PYSRC)/emitnative.c $(PYSRC)/emit.h
+	$(CC) $(CFLAGS) $(CFLAGS_PY) -DN_THUMB -c -o $@ $<
+
+# optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster)
+$(BUILD)/vm.o: $(PYSRC)/vm.c
+	$(CC) $(CFLAGS) $(CFLAGS_PY) -O3 -c -o $@ $<
+
+$(BUILD)/parse.o: $(PYSRC)/grammar.h
+$(BUILD)/compile.o: $(PYSRC)/grammar.h
+$(BUILD)/emitcpy.o: $(PYSRC)/emit.h
+$(BUILD)/emitbc.o: $(PYSRC)/emit.h
+
+clean:
+	/bin/rm -r $(BUILD)
diff --git a/py/main.c b/unix/main.c
similarity index 95%
rename from py/main.c
rename to unix/main.c
index 2059a8fc488c108c7fd120a591837bb9c153ecfa..2a1103c45f6d996042d08cea73b06366308c3cf5 100644
--- a/py/main.c
+++ b/unix/main.c
@@ -3,8 +3,8 @@
 #include <string.h>
 
 #include "misc.h"
+#include "mpyconfig.h"
 #include "lexer.h"
-#include "machine.h"
 #include "parse.h"
 #include "compile.h"
 #include "runtime.h"
@@ -42,6 +42,7 @@ int main(int argc, char **argv) {
 
     py_lexer_free(lex);
 
+#if !defined(MICROPY_EMIT_ENABLE_CPYTHON)
     if (1) {
         // execute it
         py_obj_t module_fun = rt_make_function_from_id(1);
@@ -52,6 +53,7 @@ int main(int argc, char **argv) {
             printf("\n");
         }
     }
+#endif
 
     rt_deinit();
 
diff --git a/unix/mpyconfig.h b/unix/mpyconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..117892b3d608bbc6700c139b6f12897e916d012e
--- /dev/null
+++ b/unix/mpyconfig.h
@@ -0,0 +1,14 @@
+// options to control how Micro Python is built
+
+//#define MICROPY_ENABLE_FLOAT
+#define MICROPY_EMIT_ENABLE_CPYTHON
+#define MICROPY_EMIT_ENABLE_X64
+//#define MICROPY_EMIT_ENABLE_THUMB
+#define MICROPY_EMIT_ENABLE_INLINE_THUMB
+
+// type definitions for the specific machine
+
+typedef int64_t machine_int_t; // must be pointer size
+typedef uint64_t machine_uint_t; // must be pointer size
+typedef void *machine_ptr_t; // must be of pointer size
+typedef double machine_float_t;