diff --git a/py/compile.c b/py/compile.c
index 418c1100bf0ec6f53e508fe9966cd1b40275222d..7c2c89fb52e437e7f3b5645b8c2d4f74051a3fc9 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -79,6 +79,8 @@ typedef enum {
 #define NATIVE_EMITTER(f) emit_native_thumb_##f
 #elif MICROPY_EMIT_ARM
 #define NATIVE_EMITTER(f) emit_native_arm_##f
+#elif MICROPY_EMIT_XTENSA
+#define NATIVE_EMITTER(f) emit_native_xtensa_##f
 #else
 #error "unknown native emitter"
 #endif
diff --git a/py/emit.h b/py/emit.h
index 885033e3d000c3de22acbc37c5449a3dd2f1080f..122df8e7d28b31d0c752091a2549a52e4d977a06 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -154,6 +154,7 @@ extern const emit_method_table_t emit_native_x64_method_table;
 extern const emit_method_table_t emit_native_x86_method_table;
 extern const emit_method_table_t emit_native_thumb_method_table;
 extern const emit_method_table_t emit_native_arm_method_table;
+extern const emit_method_table_t emit_native_xtensa_method_table;
 
 extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops;
 extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops;
@@ -164,6 +165,7 @@ emit_t *emit_native_x64_new(mp_obj_t *error_slot, mp_uint_t max_num_labels);
 emit_t *emit_native_x86_new(mp_obj_t *error_slot, mp_uint_t max_num_labels);
 emit_t *emit_native_thumb_new(mp_obj_t *error_slot, mp_uint_t max_num_labels);
 emit_t *emit_native_arm_new(mp_obj_t *error_slot, mp_uint_t max_num_labels);
+emit_t *emit_native_xtensa_new(mp_obj_t *error_slot, mp_uint_t max_num_labels);
 
 void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels);
 
@@ -172,6 +174,7 @@ void emit_native_x64_free(emit_t *emit);
 void emit_native_x86_free(emit_t *emit);
 void emit_native_thumb_free(emit_t *emit);
 void emit_native_arm_free(emit_t *emit);
+void emit_native_xtensa_free(emit_t *emit);
 
 void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope);
 void mp_emit_bc_end_pass(emit_t *emit);
diff --git a/py/emitnative.c b/py/emitnative.c
index 5a7e0ea341c42a9ad01feff24c2733b182e019ee..2e18d26b4a2c41e483dab1d9a21a942498f4c25a 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -61,7 +61,8 @@
 #if (MICROPY_EMIT_X64 && N_X64) \
     || (MICROPY_EMIT_X86 && N_X86) \
     || (MICROPY_EMIT_THUMB && N_THUMB) \
-    || (MICROPY_EMIT_ARM && N_ARM)
+    || (MICROPY_EMIT_ARM && N_ARM) \
+    || (MICROPY_EMIT_XTENSA && N_XTENSA) \
 
 // this is defined so that the assembler exports generic assembler API macros
 #define GENERIC_ASM_API (1)
@@ -139,6 +140,12 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
 #include "py/asmarm.h"
 #define EXPORT_FUN(name) emit_native_arm_##name
 
+#elif N_XTENSA
+
+// Xtensa specific stuff
+#include "py/asmxtensa.h"
+#define EXPORT_FUN(name) emit_native_xtensa_##name
+
 #else
 
 #error unknown native emitter
@@ -1965,6 +1972,21 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
                 ASM_ARM_CC_NE,
             };
             asm_arm_setcc_reg(emit->as, REG_RET, ccs[op - MP_BINARY_OP_LESS]);
+            #elif N_XTENSA
+            static uint8_t ccs[6] = {
+                ASM_XTENSA_CC_LT,
+                0x80 | ASM_XTENSA_CC_LT, // for GT we'll swap args
+                ASM_XTENSA_CC_EQ,
+                0x80 | ASM_XTENSA_CC_GE, // for LE we'll swap args
+                ASM_XTENSA_CC_GE,
+                ASM_XTENSA_CC_NE,
+            };
+            uint8_t cc = ccs[op - MP_BINARY_OP_LESS];
+            if ((cc & 0x80) == 0) {
+                asm_xtensa_setcc_reg_reg_reg(emit->as, cc, REG_RET, REG_ARG_2, reg_rhs);
+            } else {
+                asm_xtensa_setcc_reg_reg_reg(emit->as, cc & ~0x80, REG_RET, reg_rhs, REG_ARG_2);
+            }
             #else
                 #error not implemented
             #endif
diff --git a/py/mkrules.mk b/py/mkrules.mk
index d509f7b481d739c4545abe8ef33a123f52bdc9c9..f4a2363a7a135d75ff2828d519698c283ac27aff 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -49,7 +49,7 @@ $(BUILD)/%.o: %.c
 # List all native flags since the current build system doesn't have
 # the micropython configuration available. However, these flags are
 # needed to extract all qstrings
-QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB -DN_ARM
+QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB -DN_ARM -DN_XTENSA
 QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp
 
 vpath %.c . $(TOP)
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 4572fc4cc9082f3be511c43fae8ca583e39122ab..15f770573bfc13f08dfd953338a4ec2683fd975d 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -288,8 +288,13 @@
 #define MICROPY_EMIT_ARM (0)
 #endif
 
+// Whether to emit Xtensa native code
+#ifndef MICROPY_EMIT_XTENSA
+#define MICROPY_EMIT_XTENSA (0)
+#endif
+
 // Convenience definition for whether any native emitter is enabled
-#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM)
+#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA)
 
 /*****************************************************************************/
 /* Compiler configuration                                                    */
diff --git a/py/py.mk b/py/py.mk
index 87a860f7554f3ca3e4abda213f5fb0e6a0ae2008..9d2a188f1a2ff2c25b0cb332176c52fc4b75b8f7 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -130,6 +130,8 @@ PY_O_BASENAME = \
 	emitinlinethumb.o \
 	asmarm.o \
 	emitnarm.o \
+	asmxtensa.o \
+	emitnxtensa.o \
 	formatfloat.o \
 	parsenumbase.o \
 	parsenum.o \
@@ -250,7 +252,7 @@ PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o
 endif
 
 # Sources that may contain qstrings
-SRC_QSTR_IGNORE = nlr% emitnx% emitnthumb% emitnarm%
+SRC_QSTR_IGNORE = nlr% emitnx86% emitnx64% emitnthumb% emitnarm% emitnxtensa%
 SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c)
 
 # Anything that depends on FORCE will be considered out-of-date
@@ -292,6 +294,10 @@ $(PY_BUILD)/emitnarm.o: CFLAGS += -DN_ARM
 $(PY_BUILD)/emitnarm.o: py/emitnative.c
 	$(call compile_c)
 
+$(PY_BUILD)/emitnxtensa.o: CFLAGS += -DN_XTENSA
+$(PY_BUILD)/emitnxtensa.o: py/emitnative.c
+	$(call compile_c)
+
 # optimising gc for speed; 5ms down to 4ms on pybv2
 $(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)