diff --git a/py/mpconfig.h b/py/mpconfig.h
index 7ab179304c2d764e9471235aae3fcca8362d6e9d..98e9406c6bb1d7e676eda9851b72ed70e9597d6d 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -63,6 +63,16 @@
 //  - xxxx...xxx0 : a pointer to an mp_obj_base_t (unless a fake object)
 #define MICROPY_OBJ_REPR_B (1)
 
+// A MicroPython object is a machine word having the following form:
+//  - iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int with 31-bit signed value
+//  - x1111111 1qqqqqqq qqqqqqqq qqqqq110 str with 20-bit qstr value
+//  - s1111111 10000000 00000000 00000010 +/- inf
+//  - s1111111 1xxxxxxx xxxxxxxx xxxxx010 nan, x != 0
+//  - seeeeeee efffffff ffffffff ffffff10 30-bit fp, e != 0xff
+//  - pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment)
+// This scheme only works with 32-bit word size and float enabled.
+#define MICROPY_OBJ_REPR_C (2)
+
 #ifndef MICROPY_OBJ_REPR
 #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
 #endif
diff --git a/py/obj.h b/py/obj.h
index faf7e096afc48c02f11c17b12570aaafd3aeaa5e..af5652c4ec4c961cbe8f3c6fc9c6c556ed706726 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -123,6 +123,41 @@ mp_obj_t mp_obj_new_float(mp_float_t value);
 static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o)
     { return ((((mp_int_t)(o)) & 1) == 0); }
 
+#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
+
+static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
+    { return ((((mp_int_t)(o)) & 1) != 0); }
+#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
+#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
+
+#define mp_const_float_e ((mp_obj_t)((0x402df854 & ~3) | 2))
+#define mp_const_float_pi ((mp_obj_t)((0x40490fdb & ~3) | 2))
+
+static inline bool mp_obj_is_float(mp_const_obj_t o)
+    { return (((mp_uint_t)(o)) & 3) == 2 && (((mp_uint_t)(o)) & 0x7f800004) != 0x7f800004; }
+static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
+    union {
+        mp_float_t f;
+        mp_uint_t u;
+    } num = {.u = (mp_uint_t)o & ~3};
+    return num.f;
+}
+static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
+    union {
+        mp_float_t f;
+        mp_uint_t u;
+    } num = {.f = f};
+    return (mp_obj_t)((num.u & ~0x3) | 2);
+}
+
+static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o)
+    { return (((mp_uint_t)(o)) & 0x7f800007) == 0x7f800006; }
+#define MP_OBJ_QSTR_VALUE(o) ((((mp_uint_t)(o)) >> 3) & 0xfffff)
+#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 0x7f800006))
+
+static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o)
+    { return ((((mp_int_t)(o)) & 3) == 0); }
+
 #endif
 
 // Macros to convert between mp_obj_t and concrete object types.
diff --git a/py/objfloat.c b/py/objfloat.c
index 7c58f320dbc9e407277726ecb85743f0e0c353dc..81eac99bd19cf2ee428f75b814aedda83fe7672a 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -39,6 +39,8 @@
 #include <math.h>
 #include "py/formatfloat.h"
 
+#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C
+
 typedef struct _mp_obj_float_t {
     mp_obj_base_t base;
     mp_float_t value;
@@ -47,6 +49,8 @@ typedef struct _mp_obj_float_t {
 const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, M_E};
 const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, M_PI};
 
+#endif
+
 STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
     (void)kind;
     mp_float_t o_val = mp_obj_float_get(o_in);
@@ -121,6 +125,8 @@ const mp_obj_type_t mp_type_float = {
     .binary_op = float_binary_op,
 };
 
+#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C
+
 mp_obj_t mp_obj_new_float(mp_float_t value) {
     mp_obj_float_t *o = m_new(mp_obj_float_t, 1);
     o->base.type = &mp_type_float;
@@ -134,6 +140,8 @@ mp_float_t mp_obj_float_get(mp_obj_t self_in) {
     return self->value;
 }
 
+#endif
+
 STATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
     // logic here follows that of CPython
     // https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
diff --git a/py/smallint.h b/py/smallint.h
index 19b5209ec7fb63b8d22efc9f082880341297d440..d9e53ee3618792dbfb4eb1f63e96964cc1b6a3b4 100644
--- a/py/smallint.h
+++ b/py/smallint.h
@@ -32,7 +32,7 @@
 // Functions for small integer arithmetic
 
 // In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range
-#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
+#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
 
 #define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 1))
 #define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)