py: Viper can now store to global.
diff --git a/py/emitnative.c b/py/emitnative.c
index eb5b6b1..4966e37 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -903,8 +903,16 @@
 }
 
 STATIC void emit_native_store_global(emit_t *emit, qstr qstr) {
-    // not implemented
-    assert(0);
+    vtype_kind_t vtype = peek_vtype(emit);
+    if (vtype == VTYPE_PYOBJ) {
+        emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
+    } else {
+        emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
+        emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, mp_convert_native_to_obj, vtype, REG_ARG_2); // arg2 = type
+        ASM_MOV_REG_TO_REG(REG_RET, REG_ARG_2);
+    }
+    emit_call_with_imm_arg(emit, MP_F_STORE_GLOBAL, mp_store_global, qstr, REG_ARG_1); // arg1 = name
+    emit_post(emit);
 }
 
 STATIC void emit_native_store_attr(emit_t *emit, qstr qstr) {
@@ -1420,12 +1428,14 @@
 
 STATIC void emit_native_return_value(emit_t *emit) {
     DEBUG_printf("return_value\n");
-    // easy.  since we don't know who we return to, just return the raw value.
-    // runtime needs then to know our type signature, but I think that's possible.
     vtype_kind_t vtype;
     emit_pre_pop_reg(emit, &vtype, REG_RET);
     if (emit->do_viper_types) {
-        if (vtype != emit->return_vtype) {
+        if (vtype == VTYPE_PTR_NONE) {
+            if (emit->return_vtype == VTYPE_PYOBJ) {
+                ASM_MOV_IMM_TO_REG((mp_uint_t)mp_const_none, REG_RET);
+            }
+        } else if (vtype != emit->return_vtype) {
             printf("ViperTypeError: incompatible return type\n");
         }
     } else {
diff --git a/py/objfun.c b/py/objfun.c
index 83e5ade..63dbd4f 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -517,28 +517,6 @@
 typedef mp_uint_t (*viper_fun_2_t)(mp_uint_t, mp_uint_t);
 typedef mp_uint_t (*viper_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);
 
-// convert a Micro Python object to a valid value for viper, based on wanted type
-STATIC mp_uint_t convert_obj_for_viper(mp_obj_t obj, mp_uint_t type) {
-    switch (type & 3) {
-        case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj;
-        case MP_NATIVE_TYPE_BOOL:
-        case MP_NATIVE_TYPE_INT:
-        case MP_NATIVE_TYPE_UINT: return mp_obj_get_int(obj);
-        default: assert(0); return 0;
-    }
-}
-
-// convert a return value from viper to a Micro Python object based on viper return type
-STATIC mp_obj_t convert_val_from_viper(mp_uint_t val, mp_uint_t type) {
-    switch (type & 3) {
-        case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val;
-        case MP_NATIVE_TYPE_BOOL: return MP_BOOL(val);
-        case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val);
-        case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val);
-        default: assert(0); return mp_const_none;
-    }
-}
-
 STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
     mp_obj_fun_viper_t *self = self_in;
 
@@ -548,17 +526,17 @@
     if (n_args == 0) {
         ret = ((viper_fun_0_t)self->fun)();
     } else if (n_args == 1) {
-        ret = ((viper_fun_1_t)self->fun)(convert_obj_for_viper(args[0], self->type_sig >> 2));
+        ret = ((viper_fun_1_t)self->fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2));
     } else if (n_args == 2) {
-        ret = ((viper_fun_2_t)self->fun)(convert_obj_for_viper(args[0], self->type_sig >> 2), convert_obj_for_viper(args[1], self->type_sig >> 4));
+        ret = ((viper_fun_2_t)self->fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2), mp_convert_obj_to_native(args[1], self->type_sig >> 4));
     } else if (n_args == 3) {
-        ret = ((viper_fun_3_t)self->fun)(convert_obj_for_viper(args[0], self->type_sig >> 2), convert_obj_for_viper(args[1], self->type_sig >> 4), convert_obj_for_viper(args[2], self->type_sig >> 6));
+        ret = ((viper_fun_3_t)self->fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2), mp_convert_obj_to_native(args[1], self->type_sig >> 4), mp_convert_obj_to_native(args[2], self->type_sig >> 6));
     } else {
         assert(0);
         ret = 0;
     }
 
-    return convert_val_from_viper(ret, self->type_sig);
+    return mp_convert_native_to_obj(ret, self->type_sig);
 }
 
 STATIC const mp_obj_type_t mp_type_fun_viper = {
diff --git a/py/runtime.c b/py/runtime.c
index 59e47c7..f233a77 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1163,8 +1163,34 @@
     nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, msg));
 }
 
+// convert a Micro Python object to a valid native value based on type
+mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) {
+    DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type);
+    switch (type & 3) {
+        case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj;
+        case MP_NATIVE_TYPE_BOOL:
+        case MP_NATIVE_TYPE_INT:
+        case MP_NATIVE_TYPE_UINT: return mp_obj_get_int(obj);
+        default: assert(0); return 0;
+    }
+}
+
+// convert a native value to a Micro Python object based on type
+mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) {
+    DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type);
+    switch (type & 3) {
+        case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val;
+        case MP_NATIVE_TYPE_BOOL: return MP_BOOL(val);
+        case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val);
+        case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val);
+        default: assert(0); return mp_const_none;
+    }
+}
+
 // these must correspond to the respective enum
 void *const mp_fun_table[MP_F_NUMBER_OF] = {
+    mp_convert_obj_to_native,
+    mp_convert_native_to_obj,
     mp_load_const_int,
     mp_load_const_dec,
     mp_load_const_str,
@@ -1174,6 +1200,7 @@
     mp_load_attr,
     mp_load_method,
     mp_store_name,
+    mp_store_global,
     mp_store_attr,
     mp_obj_subscr,
     mp_obj_is_true,
diff --git a/py/runtime.h b/py/runtime.h
index 2feb24d..f908d9d 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -115,6 +115,9 @@
 // Raise NotImplementedError with given message
 NORETURN void mp_not_implemented(const char *msg);
 
+mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type);
+mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type);
+
 extern struct _mp_obj_list_t mp_sys_path_obj;
 extern struct _mp_obj_list_t mp_sys_argv_obj;
 #define mp_sys_path ((mp_obj_t)&mp_sys_path_obj)
diff --git a/py/runtime0.h b/py/runtime0.h
index 01504f5..dfce041 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -102,7 +102,9 @@
 } mp_binary_op_t;
 
 typedef enum {
-    MP_F_LOAD_CONST_INT = 0,
+    MP_F_CONVERT_OBJ_TO_NATIVE = 0,
+    MP_F_CONVERT_NATIVE_TO_OBJ,
+    MP_F_LOAD_CONST_INT,
     MP_F_LOAD_CONST_DEC,
     MP_F_LOAD_CONST_STR,
     MP_F_LOAD_NAME,
@@ -111,6 +113,7 @@
     MP_F_LOAD_ATTR,
     MP_F_LOAD_METHOD,
     MP_F_STORE_NAME,
+    MP_F_STORE_GLOBAL,
     MP_F_STORE_ATTR,
     MP_F_OBJ_SUBSCR,
     MP_F_OBJ_IS_TRUE,
diff --git a/tests/micropython/viper.py b/tests/micropython/viper.py
index 2ed70ad..36849ab 100644
--- a/tests/micropython/viper.py
+++ b/tests/micropython/viper.py
@@ -29,6 +29,13 @@
         total += x
     return total
 
+# accessing a global
+@micropython.viper
+def access_global():
+    global gl
+    gl = 1
+    return gl
+
 # this doesn't work at the moment
 #@micropython.viper
 #def g() -> uint:
@@ -39,3 +46,4 @@
 print(h(3))
 print(i(4, 5))
 print(viper_sum(10, 10000))
+print(access_global(), gl)
diff --git a/tests/micropython/viper.py.exp b/tests/micropython/viper.py.exp
index 6ee698f..4c30831 100644
--- a/tests/micropython/viper.py.exp
+++ b/tests/micropython/viper.py.exp
@@ -3,3 +3,4 @@
 7
 20
 49994955
+1 1