diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index d8f40346269d..9a34cc825e96 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -349,6 +349,7 @@ typedef struct XtensaOpcodeTranslators {
 } XtensaOpcodeTranslators;
 
 extern const XtensaOpcodeTranslators xtensa_core_opcodes;
+extern const XtensaOpcodeTranslators xtensa_fpu2000_opcodes;
 
 struct XtensaConfig {
     const char *name;
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 1c227380a64d..f6a53cdfc28f 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -6433,3 +6433,377 @@ const XtensaOpcodeTranslators xtensa_core_opcodes = {
     .num_opcodes = ARRAY_SIZE(core_ops),
     .opcode = core_ops,
 };
+
+
+static void translate_abs_s(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        gen_helper_abs_s(cpu_FR[arg[0]], cpu_FR[arg[1]]);
+    }
+}
+
+static void translate_add_s(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        gen_helper_add_s(cpu_FR[arg[0]], cpu_env,
+                         cpu_FR[arg[1]], cpu_FR[arg[2]]);
+    }
+}
+
+enum {
+    COMPARE_UN,
+    COMPARE_OEQ,
+    COMPARE_UEQ,
+    COMPARE_OLT,
+    COMPARE_ULT,
+    COMPARE_OLE,
+    COMPARE_ULE,
+};
+
+static void translate_compare_s(DisasContext *dc, const uint32_t arg[],
+                                const uint32_t par[])
+{
+    static void (* const helper[])(TCGv_env env, TCGv_i32 bit,
+                                   TCGv_i32 s, TCGv_i32 t) = {
+        [COMPARE_UN] = gen_helper_un_s,
+        [COMPARE_OEQ] = gen_helper_oeq_s,
+        [COMPARE_UEQ] = gen_helper_ueq_s,
+        [COMPARE_OLT] = gen_helper_olt_s,
+        [COMPARE_ULT] = gen_helper_ult_s,
+        [COMPARE_OLE] = gen_helper_ole_s,
+        [COMPARE_ULE] = gen_helper_ule_s,
+    };
+
+    if (gen_check_cpenable(dc, 0)) {
+        TCGv_i32 bit = tcg_const_i32(1 << arg[0]);
+
+        helper[par[0]](cpu_env, bit, cpu_FR[arg[1]], cpu_FR[arg[2]]);
+        tcg_temp_free(bit);
+    }
+}
+
+static void translate_float_s(DisasContext *dc, const uint32_t arg[],
+                              const uint32_t par[])
+{
+    if (gen_window_check1(dc, arg[1]) && gen_check_cpenable(dc, 0)) {
+        TCGv_i32 scale = tcg_const_i32(-arg[2]);
+
+        if (par[0]) {
+            gen_helper_uitof(cpu_FR[arg[0]], cpu_env, cpu_R[arg[1]], scale);
+        } else {
+            gen_helper_itof(cpu_FR[arg[0]], cpu_env, cpu_R[arg[1]], scale);
+        }
+        tcg_temp_free(scale);
+    }
+}
+
+static void translate_ftoi_s(DisasContext *dc, const uint32_t arg[],
+                             const uint32_t par[])
+{
+    if (gen_window_check1(dc, arg[0]) && gen_check_cpenable(dc, 0)) {
+        TCGv_i32 rounding_mode = tcg_const_i32(par[0]);
+        TCGv_i32 scale = tcg_const_i32(arg[2]);
+
+        if (par[1]) {
+            gen_helper_ftoui(cpu_R[arg[0]], cpu_FR[arg[1]],
+                             rounding_mode, scale);
+        } else {
+            gen_helper_ftoi(cpu_R[arg[0]], cpu_FR[arg[1]],
+                            rounding_mode, scale);
+        }
+        tcg_temp_free(rounding_mode);
+        tcg_temp_free(scale);
+    }
+}
+
+static void translate_ldsti(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_window_check1(dc, arg[1]) && gen_check_cpenable(dc, 0)) {
+        TCGv_i32 addr = tcg_temp_new_i32();
+
+        tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]);
+        gen_load_store_alignment(dc, 2, addr, false);
+        if (par[0]) {
+            tcg_gen_qemu_st32(cpu_FR[arg[0]], addr, dc->cring);
+        } else {
+            tcg_gen_qemu_ld32u(cpu_FR[arg[0]], addr, dc->cring);
+        }
+        if (par[1]) {
+            tcg_gen_mov_i32(cpu_R[arg[1]], addr);
+        }
+        tcg_temp_free(addr);
+    }
+}
+
+static void translate_ldstx(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_window_check2(dc, arg[1], arg[2]) && gen_check_cpenable(dc, 0)) {
+        TCGv_i32 addr = tcg_temp_new_i32();
+
+        tcg_gen_add_i32(addr, cpu_R[arg[1]], cpu_R[arg[2]]);
+        gen_load_store_alignment(dc, 2, addr, false);
+        if (par[0]) {
+            tcg_gen_qemu_st32(cpu_FR[arg[0]], addr, dc->cring);
+        } else {
+            tcg_gen_qemu_ld32u(cpu_FR[arg[0]], addr, dc->cring);
+        }
+        if (par[1]) {
+            tcg_gen_mov_i32(cpu_R[arg[1]], addr);
+        }
+        tcg_temp_free(addr);
+    }
+}
+
+static void translate_madd_s(DisasContext *dc, const uint32_t arg[],
+                             const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        gen_helper_madd_s(cpu_FR[arg[0]], cpu_env,
+                          cpu_FR[arg[0]], cpu_FR[arg[1]], cpu_FR[arg[2]]);
+    }
+}
+
+static void translate_mov_s(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_FR[arg[1]]);
+    }
+}
+
+static void translate_movcond_s(DisasContext *dc, const uint32_t arg[],
+                                const uint32_t par[])
+{
+    if (gen_window_check1(dc, arg[2]) && gen_check_cpenable(dc, 0)) {
+        TCGv_i32 zero = tcg_const_i32(0);
+
+        tcg_gen_movcond_i32(par[0], cpu_FR[arg[0]],
+                            cpu_R[arg[2]], zero,
+                            cpu_FR[arg[1]], cpu_FR[arg[2]]);
+        tcg_temp_free(zero);
+    }
+}
+
+static void translate_movp_s(DisasContext *dc, const uint32_t arg[],
+                             const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        TCGv_i32 zero = tcg_const_i32(0);
+        TCGv_i32 tmp = tcg_temp_new_i32();
+
+        tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << arg[2]);
+        tcg_gen_movcond_i32(par[0],
+                            cpu_FR[arg[0]], tmp, zero,
+                            cpu_FR[arg[1]], cpu_FR[arg[0]]);
+        tcg_temp_free(tmp);
+        tcg_temp_free(zero);
+    }
+}
+
+static void translate_mul_s(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        gen_helper_mul_s(cpu_FR[arg[0]], cpu_env,
+                         cpu_FR[arg[1]], cpu_FR[arg[2]]);
+    }
+}
+
+static void translate_msub_s(DisasContext *dc, const uint32_t arg[],
+                             const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        gen_helper_msub_s(cpu_FR[arg[0]], cpu_env,
+                          cpu_FR[arg[0]], cpu_FR[arg[1]], cpu_FR[arg[2]]);
+    }
+}
+
+static void translate_neg_s(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        gen_helper_neg_s(cpu_FR[arg[0]], cpu_FR[arg[1]]);
+    }
+}
+
+static void translate_rfr_s(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_window_check1(dc, arg[0]) &&
+        gen_check_cpenable(dc, 0)) {
+        tcg_gen_mov_i32(cpu_R[arg[0]], cpu_FR[arg[1]]);
+    }
+}
+
+static void translate_sub_s(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_check_cpenable(dc, 0)) {
+        gen_helper_sub_s(cpu_FR[arg[0]], cpu_env,
+                         cpu_FR[arg[1]], cpu_FR[arg[2]]);
+    }
+}
+
+static void translate_wfr_s(DisasContext *dc, const uint32_t arg[],
+                            const uint32_t par[])
+{
+    if (gen_window_check1(dc, arg[1]) &&
+        gen_check_cpenable(dc, 0)) {
+        tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_R[arg[1]]);
+    }
+}
+
+static const XtensaOpcodeOps fpu2000_ops[] = {
+    {
+        .name = "abs.s",
+        .translate = translate_abs_s,
+    }, {
+        .name = "add.s",
+        .translate = translate_add_s,
+    }, {
+        .name = "ceil.s",
+        .translate = translate_ftoi_s,
+        .par = (const uint32_t[]){float_round_up, false},
+    }, {
+        .name = "float.s",
+        .translate = translate_float_s,
+        .par = (const uint32_t[]){false},
+    }, {
+        .name = "floor.s",
+        .translate = translate_ftoi_s,
+        .par = (const uint32_t[]){float_round_down, false},
+    }, {
+        .name = "lsi",
+        .translate = translate_ldsti,
+        .par = (const uint32_t[]){false, false},
+    }, {
+        .name = "lsiu",
+        .translate = translate_ldsti,
+        .par = (const uint32_t[]){false, true},
+    }, {
+        .name = "lsx",
+        .translate = translate_ldstx,
+        .par = (const uint32_t[]){false, false},
+    }, {
+        .name = "lsxu",
+        .translate = translate_ldstx,
+        .par = (const uint32_t[]){false, true},
+    }, {
+        .name = "madd.s",
+        .translate = translate_madd_s,
+    }, {
+        .name = "mov.s",
+        .translate = translate_mov_s,
+    }, {
+        .name = "moveqz.s",
+        .translate = translate_movcond_s,
+        .par = (const uint32_t[]){TCG_COND_EQ},
+    }, {
+        .name = "movf.s",
+        .translate = translate_movp_s,
+        .par = (const uint32_t[]){TCG_COND_EQ},
+    }, {
+        .name = "movgez.s",
+        .translate = translate_movcond_s,
+        .par = (const uint32_t[]){TCG_COND_GE},
+    }, {
+        .name = "movltz.s",
+        .translate = translate_movcond_s,
+        .par = (const uint32_t[]){TCG_COND_LT},
+    }, {
+        .name = "movnez.s",
+        .translate = translate_movcond_s,
+        .par = (const uint32_t[]){TCG_COND_NE},
+    }, {
+        .name = "movt.s",
+        .translate = translate_movp_s,
+        .par = (const uint32_t[]){TCG_COND_NE},
+    }, {
+        .name = "msub.s",
+        .translate = translate_msub_s,
+    }, {
+        .name = "mul.s",
+        .translate = translate_mul_s,
+    }, {
+        .name = "neg.s",
+        .translate = translate_neg_s,
+    }, {
+        .name = "oeq.s",
+        .translate = translate_compare_s,
+        .par = (const uint32_t[]){COMPARE_OEQ},
+    }, {
+        .name = "ole.s",
+        .translate = translate_compare_s,
+        .par = (const uint32_t[]){COMPARE_OLE},
+    }, {
+        .name = "olt.s",
+        .translate = translate_compare_s,
+        .par = (const uint32_t[]){COMPARE_OLT},
+    }, {
+        .name = "rfr.s",
+        .translate = translate_rfr_s,
+    }, {
+        .name = "round.s",
+        .translate = translate_ftoi_s,
+        .par = (const uint32_t[]){float_round_nearest_even, false},
+    }, {
+        .name = "ssi",
+        .translate = translate_ldsti,
+        .par = (const uint32_t[]){true, false},
+    }, {
+        .name = "ssiu",
+        .translate = translate_ldsti,
+        .par = (const uint32_t[]){true, true},
+    }, {
+        .name = "ssx",
+        .translate = translate_ldstx,
+        .par = (const uint32_t[]){true, false},
+    }, {
+        .name = "ssxu",
+        .translate = translate_ldstx,
+        .par = (const uint32_t[]){true, true},
+    }, {
+        .name = "sub.s",
+        .translate = translate_sub_s,
+    }, {
+        .name = "trunc.s",
+        .translate = translate_ftoi_s,
+        .par = (const uint32_t[]){float_round_to_zero, false},
+    }, {
+        .name = "ueq.s",
+        .translate = translate_compare_s,
+        .par = (const uint32_t[]){COMPARE_UEQ},
+    }, {
+        .name = "ufloat.s",
+        .translate = translate_float_s,
+        .par = (const uint32_t[]){true},
+    }, {
+        .name = "ule.s",
+        .translate = translate_compare_s,
+        .par = (const uint32_t[]){COMPARE_ULE},
+    }, {
+        .name = "ult.s",
+        .translate = translate_compare_s,
+        .par = (const uint32_t[]){COMPARE_ULT},
+    }, {
+        .name = "un.s",
+        .translate = translate_compare_s,
+        .par = (const uint32_t[]){COMPARE_UN},
+    }, {
+        .name = "utrunc.s",
+        .translate = translate_ftoi_s,
+        .par = (const uint32_t[]){float_round_to_zero, true},
+    }, {
+        .name = "wfr.s",
+        .translate = translate_wfr_s,
+    },
+};
+
+const XtensaOpcodeTranslators xtensa_fpu2000_opcodes = {
+    .num_opcodes = ARRAY_SIZE(fpu2000_ops),
+    .opcode = fpu2000_ops,
+};
