[{"id":3676357,"web_url":"http://patchwork.ozlabs.org/comment/3676357/","msgid":"<b78cb17a-65fe-4394-8d62-8caa3447065b@linaro.org>","list_archive_url":null,"date":"2026-04-12T18:21:29","subject":"Re: [PATCH 2/9] target/mips: add Octeon arithmetic and memory\n instructions","submitter":{"id":85046,"url":"http://patchwork.ozlabs.org/api/people/85046/","name":"Philippe Mathieu-Daudé","email":"philmd@linaro.org"},"content":"Hi James,\n\nOn 11/4/26 09:06, James Hilliard wrote:\n> Octeon CPUs define additional integer, memory, and multiply operations\n> beyond the base MIPS64 ISA. Add the missing decode and helper support\n> for the remaining regular Octeon instructions used by existing user-mode\n> workloads.\n> \n> This covers the indexed unaligned load/store forms, cache block zero\n> operations, the Octeon multiply family, population count handling, and\n> related arithmetic and memory operations in the translator and helper\n> layer.\n\nThanks for this series! (Please include a cover letter for v2).\n\nFor historical background, see my previous question regarding testing:\nhttps://lore.kernel.org/qemu-devel/a616c83d-068e-46a0-80b7-878425005317@linaro.org/\n\nWe need few pieces of guest code to test this feature, because we\ndon't want to maintain bitrotten code.\n\n> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>\n> ---\n>   target/mips/cpu-defs.c.inc         |  10 +-\n>   target/mips/cpu.h                  |  12 +++\n>   target/mips/helper.h               |   2 +\n>   target/mips/system/machine.c       |  43 ++++++++\n>   target/mips/tcg/octeon.decode      |  28 ++++-\n>   target/mips/tcg/octeon_translate.c | 163 +++++++++++++++++++++++++++--\n>   target/mips/tcg/op_helper.c        |  84 +++++++++++++++\n>   7 files changed, 331 insertions(+), 11 deletions(-)\n> \n> diff --git a/target/mips/cpu-defs.c.inc b/target/mips/cpu-defs.c.inc\n> index d93b9d341a..6c084fcaea 100644\n> --- a/target/mips/cpu-defs.c.inc\n> +++ b/target/mips/cpu-defs.c.inc\n> @@ -997,7 +997,8 @@ const mips_def_t mips_defs[] =\n>           .CP0_PRid = 0x000D9100,\n>           .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |\n>                          (MMU_TYPE_R4000 << CP0C0_MT),\n> -        .CP0_Config1 = MIPS_CONFIG1 | (0x3F << CP0C1_MMU) |\n> +        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) |\n> +                       (0x3F << CP0C1_MMU) |\n>                          (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |\n>                          (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |\n>                          (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),\n> @@ -1011,7 +1012,12 @@ const mips_def_t mips_defs[] =\n>           .CP0_PageGrain = (1 << CP0PG_ELPA),\n>           .SYNCI_Step = 32,\n>           .CCRes = 2,\n> -        .CP0_Status_rw_bitmask = 0x12F8FFFF,\n> +        .CP0_Status_rw_bitmask = 0x36F8FFFF,\n> +        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |\n> +                    (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |\n> +                    (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),\n> +        .CP1_fcr31 = 0,\n> +        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,\n>           .SEGBITS = 42,\n>           .PABITS = 49,\n>           .insn_flags = CPU_MIPS64R2 | INSN_OCTEON,\n\nExposing these CPU features to the guest should be the last patch.\n\n> diff --git a/target/mips/cpu.h b/target/mips/cpu.h\n> index ac81470576..98cd7ae83e 100644\n> --- a/target/mips/cpu.h\n> +++ b/target/mips/cpu.h\n> @@ -497,6 +497,18 @@ struct TCState {\n>       target_ulong CP0_TCScheFBack;\n>       int32_t CP0_Debug_tcstatus;\n>       target_ulong CP0_UserLocal;\n> +    target_ulong MPL0;\n> +    target_ulong MPL1;\n> +    target_ulong MPL2;\n> +    target_ulong MPL3;\n> +    target_ulong MPL4;\n> +    target_ulong MPL5;\n> +    target_ulong P0;\n> +    target_ulong P1;\n> +    target_ulong P2;\n> +    target_ulong P3;\n> +    target_ulong P4;\n> +    target_ulong P5;\n\nThis CPU only exists in 64-bit variant, so please directly start with\nuint64_t (we try to remove target_ulong uses).\n\nWe usually model banked registers as array:\n\n   uint64_t MPL[2 * 3];\n\nAlthough maybe having an octeon field could make the code easier to\nfollow (like the other octeon_crypto structure you introduce):\n\n   struct {\n       uint64_t MPL[2 * 3];\n       uint64_t P[2 * 3];\n   } octeon;\n\n>   \n>       int32_t msacsr;\n>   \n> diff --git a/target/mips/helper.h b/target/mips/helper.h\n> index b6cd53c853..3c9f67ec40 100644\n> --- a/target/mips/helper.h\n> +++ b/target/mips/helper.h\n> @@ -24,6 +24,8 @@ DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl)\n>   DEF_HELPER_3(crc32, tl, tl, tl, i32)\n>   DEF_HELPER_3(crc32c, tl, tl, tl, i32)\n>   DEF_HELPER_FLAGS_4(rotx, TCG_CALL_NO_RWG_SE, tl, tl, i32, i32, i32)\n> +DEF_HELPER_3(octeon_vmulu, tl, env, tl, tl)\n> +DEF_HELPER_3(octeon_v3mulu, tl, env, tl, tl)\n>   \n>   /* microMIPS functions */\n>   DEF_HELPER_4(lwm, void, env, tl, tl, i32)\n> diff --git a/target/mips/system/machine.c b/target/mips/system/machine.c\n> index 473d3ab036..1ea5907e55 100644\n> --- a/target/mips/system/machine.c\n> +++ b/target/mips/system/machine.c\n> @@ -118,6 +118,27 @@ static const VMStateDescription vmstate_inactive_tc = {\n>       .fields = vmstate_tc_fields\n>   };\n>   \n> +static const VMStateDescription vmstate_octeon_multiplier_tc = {\n> +    .name = \"cpu/tc/octeon_multiplier\",\n> +    .version_id = 1,\n> +    .minimum_version_id = 1,\n> +    .fields = (const VMStateField[]) {\n> +        VMSTATE_UINTTL(MPL0, TCState),\n> +        VMSTATE_UINTTL(MPL1, TCState),\n> +        VMSTATE_UINTTL(MPL2, TCState),\n> +        VMSTATE_UINTTL(MPL3, TCState),\n> +        VMSTATE_UINTTL(MPL4, TCState),\n> +        VMSTATE_UINTTL(MPL5, TCState),\n> +        VMSTATE_UINTTL(P0, TCState),\n> +        VMSTATE_UINTTL(P1, TCState),\n> +        VMSTATE_UINTTL(P2, TCState),\n> +        VMSTATE_UINTTL(P3, TCState),\n> +        VMSTATE_UINTTL(P4, TCState),\n> +        VMSTATE_UINTTL(P5, TCState),\n> +        VMSTATE_END_OF_LIST()\n> +    }\n> +};\n> +\n>   /* MVP state */\n>   \n>   static const VMStateDescription vmstate_mvp = {\n> @@ -237,6 +258,27 @@ static const VMStateDescription mips_vmstate_timer = {\n>       }\n>   };\n>   \n> +static bool mips_octeon_multiplier_needed(void *opaque)\n> +{\n> +    MIPSCPU *cpu = opaque;\n> +\n> +    return cpu->env.insn_flags & INSN_OCTEON;\n> +}\n> +\n> +static const VMStateDescription mips_vmstate_octeon_multiplier = {\n> +    .name = \"cpu/octeon_multiplier\",\n> +    .version_id = 1,\n> +    .minimum_version_id = 1,\n> +    .needed = mips_octeon_multiplier_needed,\n> +    .fields = (const VMStateField[]) {\n> +        VMSTATE_STRUCT(env.active_tc, MIPSCPU, 1,\n> +                       vmstate_octeon_multiplier_tc, TCState),\n> +        VMSTATE_STRUCT_ARRAY(env.tcs, MIPSCPU, MIPS_SHADOW_SET_MAX, 1,\n> +                             vmstate_octeon_multiplier_tc, TCState),\n> +        VMSTATE_END_OF_LIST()\n> +    }\n> +};\n> +\n>   const VMStateDescription vmstate_mips_cpu = {\n>       .name = \"cpu\",\n>       .version_id = 21,\n> @@ -353,6 +395,7 @@ const VMStateDescription vmstate_mips_cpu = {\n>       },\n>       .subsections = (const VMStateDescription * const []) {\n>           &mips_vmstate_timer,\n> +        &mips_vmstate_octeon_multiplier,\n>           NULL\n>       }\n>   };\n> diff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode\n> index 102a05860d..d90a194b54 100644\n> --- a/target/mips/tcg/octeon.decode\n> +++ b/target/mips/tcg/octeon.decode\n> @@ -30,6 +30,8 @@ BBIT         11 set:1 . 10 rs:5 ..... offset:s16 p=%bbit_p\n>   # SNEI rt, rs, immediate\n>   \n>   @r3          ...... rs:5 rt:5 rd:5 ..... ......\n> +&cmp3        rs rt rd ne\n> +&cmpi        rs rt imm ne\n>   %bitfield_p  0:1 6:5\n>   @bitfield    ...... rs:5 rt:5 lenm1:5 ..... ..... . p=%bitfield_p\n>   \n> @@ -38,12 +40,34 @@ DMUL         011100 ..... ..... ..... 00000 000011 @r3\n>   EXTS         011100 ..... ..... ..... ..... 11101 . @bitfield\n>   CINS         011100 ..... ..... ..... ..... 11001 . @bitfield\n>   POP          011100 rs:5 00000 rd:5 00000 10110 dw:1\n> -SEQNE        011100 rs:5 rt:5 rd:5 00000 10101 ne:1\n> -SEQNEI       011100 rs:5 rt:5 imm:s10 10111 ne:1\n> +SEQ          011100 rs:5 rt:5 rd:5 00000 101010 &cmp3 ne=0\n> +SNE          011100 rs:5 rt:5 rd:5 00000 101011 &cmp3 ne=1\n> +SEQI         011100 rs:5 rt:5 imm:s10 101110 &cmpi ne=0\n> +SNEI         011100 rs:5 rt:5 imm:s10 101111 &cmpi ne=1\n> +&r2          rs rt\n> +MTM0         011100 rs:5 rt:5 00000 00000 001000 &r2\n> +MTP0         011100 rs:5 rt:5 00000 00000 001001 &r2\n> +MTP1         011100 rs:5 rt:5 00000 00000 001010 &r2\n> +MTP2         011100 rs:5 rt:5 00000 00000 001011 &r2\n> +MTM1         011100 rs:5 rt:5 00000 00000 001100 &r2\n> +MTM2         011100 rs:5 rt:5 00000 00000 001101 &r2\n> +VMULU        011100 ..... ..... ..... 00000 001111 @r3\n> +V3MULU       011100 ..... ..... ..... 00000 010001 @r3\n> +\n> +&saa         base rt\n> +@saa         ...... base:5 rt:5 ................ &saa\n> +SAA          011100 ..... ..... 00000 00000 011000 @saa\n> +SAAD         011100 ..... ..... 00000 00000 011001 @saa\n> +\n> +&zcb         base\n> +ZCB          011100 base:5 00000 00000 11100 011111 &zcb\n>   \n>   &lx          base index rd\n>   @lx          ...... base:5 index:5 rd:5 ...... ..... &lx\n>   LWX          011111 ..... ..... ..... 00000 001010 @lx\n>   LHX          011111 ..... ..... ..... 00100 001010 @lx\n> +LHUX         011111 ..... ..... ..... 10100 001010 @lx\n>   LBUX         011111 ..... ..... ..... 00110 001010 @lx\n> +LWUX         011111 ..... ..... ..... 10000 001010 @lx\n> +LBX          011111 ..... ..... ..... 10110 001010 @lx\n>   LDX          011111 ..... ..... ..... 01000 001010 @lx\n> diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c\n> index b2eca29e06..67b8634dff 100644\n> --- a/target/mips/tcg/octeon_translate.c\n> +++ b/target/mips/tcg/octeon_translate.c\n> @@ -13,6 +13,8 @@\n>   /* Include the auto-generated decoder.  */\n>   #include \"decode-octeon.c.inc\"\n>   \n> +typedef void gen_helper_lmi(TCGv, TCGv_ptr, TCGv, TCGv);\n> +\n>   static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a)\n>   {\n>       TCGv p;\n> @@ -45,7 +47,7 @@ static bool trans_BADDU(DisasContext *ctx, arg_BADDU *a)\n>   {\n>       TCGv t0, t1;\n>   \n> -    if (a->rt == 0) {\n> +    if (a->rd == 0) {\n\nBug fix? Distinct patch please.\n\n>           /* nop */\n>           return true;\n>       }\n> @@ -56,7 +58,8 @@ static bool trans_BADDU(DisasContext *ctx, arg_BADDU *a)\n>       gen_load_gpr(t1, a->rt);\n>   \n>       tcg_gen_add_tl(t0, t0, t1);\n> -    tcg_gen_andi_i64(cpu_gpr[a->rd], t0, 0xff);\n> +    tcg_gen_andi_tl(t0, t0, 0xff);\n> +    gen_store_gpr(t0, a->rd);\n>       return true;\n>   }\n>   \n> @@ -64,7 +67,7 @@ static bool trans_DMUL(DisasContext *ctx, arg_DMUL *a)\n>   {\n>       TCGv t0, t1;\n>   \n> -    if (a->rt == 0) {\n> +    if (a->rd == 0) {\n\nDitto.\n\n>           /* nop */\n>           return true;\n>       }\n> @@ -74,7 +77,8 @@ static bool trans_DMUL(DisasContext *ctx, arg_DMUL *a)\n>       gen_load_gpr(t0, a->rs);\n>       gen_load_gpr(t1, a->rt);\n>   \n> -    tcg_gen_mul_i64(cpu_gpr[a->rd], t0, t1);\n> +    tcg_gen_mul_tl(t0, t0, t1);\n> +    gen_store_gpr(t0, a->rd);\n>       return true;\n>   }\n>   \n> @@ -122,14 +126,14 @@ static bool trans_POP(DisasContext *ctx, arg_POP *a)\n>       t0 = tcg_temp_new();\n>       gen_load_gpr(t0, a->rs);\n>       if (!a->dw) {\n> -        tcg_gen_andi_i64(t0, t0, 0xffffffff);\n> +        tcg_gen_andi_tl(t0, t0, 0xffffffff);\n\nNo, please avoid *_tl() helpers in this 64-bit only translator.\n\n>       }\n>       tcg_gen_ctpop_tl(t0, t0);\n>       gen_store_gpr(t0, a->rd);\n>       return true;\n>   }\n>   \n> -static bool trans_SEQNE(DisasContext *ctx, arg_SEQNE *a)\n> +static bool trans_seqne(DisasContext *ctx, const arg_cmp3 *a)\n>   {\n>       TCGv t0, t1;\n>   \n> @@ -152,7 +156,17 @@ static bool trans_SEQNE(DisasContext *ctx, arg_SEQNE *a)\n>       return true;\n>   }\n>   \n> -static bool trans_SEQNEI(DisasContext *ctx, arg_SEQNEI *a)\n> +static bool trans_SEQ(DisasContext *ctx, arg_cmp3 *a)\n> +{\n> +    return trans_seqne(ctx, a);\n> +}\n> +\n> +static bool trans_SNE(DisasContext *ctx, arg_cmp3 *a)\n> +{\n> +    return trans_seqne(ctx, a);\n> +}\n> +\n> +static bool trans_seqnei(DisasContext *ctx, const arg_cmpi *a)\n>   {\n>       TCGv t0;\n>   \n> @@ -175,6 +189,16 @@ static bool trans_SEQNEI(DisasContext *ctx, arg_SEQNEI *a)\n>       return true;\n>   }\n>   \n> +static bool trans_SEQI(DisasContext *ctx, arg_cmpi *a)\n> +{\n> +    return trans_seqnei(ctx, a);\n> +}\n> +\n> +static bool trans_SNEI(DisasContext *ctx, arg_cmpi *a)\n> +{\n> +    return trans_seqnei(ctx, a);\n> +}\n\nPlease move these changes in a preliminary patch to help reviewers.\n\n>   static bool trans_lx(DisasContext *ctx, arg_lx *a, MemOp mop)\n>   {\n>       gen_lx(ctx, a->rd, a->base, a->index, mop);\n> @@ -182,7 +206,132 @@ static bool trans_lx(DisasContext *ctx, arg_lx *a, MemOp mop)\n>       return true;\n>   }\n>   \n> +static bool trans_saa(DisasContext *ctx, arg_saa *a, MemOp mop)\n> +{\n> +    TCGv addr = tcg_temp_new();\n> +    MemOp amo = mo_endian(ctx) | mop | ctx->default_tcg_memop_mask;\n> +\n> +    gen_base_offset_addr(ctx, addr, a->base, 0);\n> +\n> +    if (mop == MO_UQ) {\n> +        TCGv value = tcg_temp_new();\n> +        TCGv old = tcg_temp_new();\n> +\n> +        gen_load_gpr(value, a->rt);\n> +        tcg_gen_atomic_fetch_add_tl(old, addr, value, ctx->mem_idx, amo);\n> +    } else {\n> +        TCGv value = tcg_temp_new();\n> +        TCGv_i32 value32 = tcg_temp_new_i32();\n> +        TCGv_i32 old = tcg_temp_new_i32();\n> +\n> +        gen_load_gpr(value, a->rt);\n> +        tcg_gen_trunc_tl_i32(value32, value);\n> +        tcg_gen_atomic_fetch_add_i32(old, addr, value32, ctx->mem_idx, amo);\n> +    }\n> +\n> +    return true;\n> +}\n> +\n> +static bool trans_ZCB(DisasContext *ctx, arg_zcb *a)\n> +{\n> +    TCGv addr = tcg_temp_new();\n> +    TCGv line = tcg_temp_new();\n> +    TCGv zero = tcg_constant_tl(0);\n> +\n> +    gen_base_offset_addr(ctx, addr, a->base, 0);\n> +\n> +    /*\n> +     * Octeon zcb operates on a cache block. Model it as zeroing the\n> +     * containing 128-byte line in memory.\n> +     */\n> +    tcg_gen_andi_tl(line, addr, ~((target_ulong)127));\n> +\n> +    for (int i = 0; i < 16; i++) {\n> +        TCGv slot = tcg_temp_new();\n> +\n> +        tcg_gen_addi_tl(slot, line, i * 8);\n> +        tcg_gen_qemu_st_tl(zero, slot, ctx->mem_idx, mo_endian(ctx) | MO_UQ);\n> +    }\n> +\n> +    return true;\n> +}\n> +\n> +static void octeon_store_tc_field(ptrdiff_t offset, TCGv value)\n> +{\n> +    tcg_gen_st_tl(value, tcg_env, offset);\n> +}\n> +\n> +static void octeon_zero_partial_product_state(void)\n> +{\n> +    TCGv zero = tcg_constant_tl(0);\n> +\n> +    octeon_store_tc_field(offsetof(CPUMIPSState, active_tc.P0), zero);\n> +    octeon_store_tc_field(offsetof(CPUMIPSState, active_tc.P1), zero);\n> +    octeon_store_tc_field(offsetof(CPUMIPSState, active_tc.P2), zero);\n> +    octeon_store_tc_field(offsetof(CPUMIPSState, active_tc.P3), zero);\n> +    octeon_store_tc_field(offsetof(CPUMIPSState, active_tc.P4), zero);\n> +    octeon_store_tc_field(offsetof(CPUMIPSState, active_tc.P5), zero);\n> +}\n> +\n> +static bool trans_mtm(DisasContext *ctx, arg_r2 *a, ptrdiff_t offset,\n> +                      ptrdiff_t high_offset)\n> +{\n> +    TCGv value = tcg_temp_new();\n> +\n> +    gen_load_gpr(value, a->rs);\n> +    octeon_store_tc_field(offset, value);\n> +    gen_load_gpr(value, a->rt);\n> +    octeon_store_tc_field(high_offset, value);\n> +    octeon_zero_partial_product_state();\n> +    return true;\n> +}\n> +\n> +static bool trans_mtp(DisasContext *ctx, arg_r2 *a, ptrdiff_t offset,\n> +                      ptrdiff_t high_offset)\n> +{\n> +    TCGv value = tcg_temp_new();\n> +\n> +    gen_load_gpr(value, a->rs);\n> +    octeon_store_tc_field(offset, value);\n> +    gen_load_gpr(value, a->rt);\n> +    octeon_store_tc_field(high_offset, value);\n> +    return true;\n> +}\n> +\n> +static bool trans_vmul(DisasContext *ctx, arg_decode_ext_octeon1 *a,\n> +                       gen_helper_lmi *helper)\n> +{\n> +    TCGv lhs = tcg_temp_new();\n> +    TCGv rhs = tcg_temp_new();\n> +    TCGv result = tcg_temp_new();\n> +\n> +    gen_load_gpr(lhs, a->rs);\n> +    gen_load_gpr(rhs, a->rt);\n> +    helper(result, tcg_env, lhs, rhs);\n> +    gen_store_gpr(result, a->rd);\n> +    return true;\n> +}\n> +\n> +TRANS(SAA,  trans_saa, MO_UL);\n> +TRANS(SAAD, trans_saa, MO_UQ);\n> +TRANS(LBX,  trans_lx, MO_SB);\n>   TRANS(LBUX, trans_lx, MO_UB);\n>   TRANS(LHX,  trans_lx, MO_SW);\n> +TRANS(LHUX, trans_lx, MO_UW);\n>   TRANS(LWX,  trans_lx, MO_SL);\n> +TRANS(LWUX, trans_lx, MO_UL);\n>   TRANS(LDX,  trans_lx, MO_UQ);\n> +TRANS(MTM0, trans_mtm, offsetof(CPUMIPSState, active_tc.MPL0),\n> +      offsetof(CPUMIPSState, active_tc.MPL3));\n> +TRANS(MTM1, trans_mtm, offsetof(CPUMIPSState, active_tc.MPL1),\n> +      offsetof(CPUMIPSState, active_tc.MPL4));\n> +TRANS(MTM2, trans_mtm, offsetof(CPUMIPSState, active_tc.MPL2),\n> +      offsetof(CPUMIPSState, active_tc.MPL5));\n> +TRANS(MTP0, trans_mtp, offsetof(CPUMIPSState, active_tc.P0),\n> +      offsetof(CPUMIPSState, active_tc.P3));\n> +TRANS(MTP1, trans_mtp, offsetof(CPUMIPSState, active_tc.P1),\n> +      offsetof(CPUMIPSState, active_tc.P4));\n> +TRANS(MTP2, trans_mtp, offsetof(CPUMIPSState, active_tc.P2),\n> +      offsetof(CPUMIPSState, active_tc.P5));\n\nTRANS() takes a VARARG list, so using the array suggestion we can\neasily rework the helpers and have simply:\n\nTRANS(MTM0, trans_mtm, 0)\nTRANS(MTM1, trans_mtm, 1)\nTRANS(MTM2, trans_mtm, 2)\nTRANS(MTP0, trans_mtp, 0)\nTRANS(MTP1, trans_mtp, 1)\nTRANS(MTP2, trans_mtp, 2)\n\n> +TRANS(VMULU, trans_vmul, gen_helper_octeon_vmulu);\n> +TRANS(V3MULU, trans_vmul, gen_helper_octeon_v3mulu);\n> diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c\n> index 4502ae2b5b..d2398b6426 100644\n> --- a/target/mips/tcg/op_helper.c\n> +++ b/target/mips/tcg/op_helper.c\n> @@ -144,6 +144,90 @@ target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx,\n>       return (int64_t)(int32_t)(uint32_t)tmp5;\n>   }\n>   \n> +static void octeon_addc(uint64_t *res, int count, uint64_t value, int index)\n> +{\n> +    while (index < count) {\n> +        uint64_t old = res[index];\n> +\n> +        res[index] += value;\n> +        if (res[index] >= old) {\n> +            break;\n> +        }\n> +        value = 1;\n> +        index++;\n> +    }\n> +}\n> +\n> +target_ulong helper_octeon_vmulu(CPUMIPSState *env, target_ulong arg1,\n> +                                 target_ulong arg2)\n\ns/target_ulong/uint64_t/\n\n> +{\n> +    uint64_t lo, hi;\n> +    uint64_t res[3] = {};\n> +\n> +    mulu64(&lo, &hi, env->active_tc.MPL0, arg1);\n\n(See, you implicitly use target_ulong as uint64_t)\n\n> +    res[0] = lo;\n> +    res[1] = hi;\n> +\n> +    mulu64(&lo, &hi, env->active_tc.MPL1, arg1);\n> +    octeon_addc(res, 3, lo, 1);\n> +    octeon_addc(res, 3, hi, 2);\n> +\n> +    octeon_addc(res, 3, arg2, 0);\n> +    octeon_addc(res, 3, env->active_tc.P0, 0);\n> +    octeon_addc(res, 3, env->active_tc.P1, 1);\n> +\n> +    env->active_tc.P0 = res[1];\n> +    env->active_tc.P1 = res[2];\n> +    return res[0];\n> +}\n> +\n> +target_ulong helper_octeon_v3mulu(CPUMIPSState *env, target_ulong arg1,\n> +                                  target_ulong arg2)\n\nDitto.\n\n> +{\n> +    uint64_t lo, hi;\n> +    uint64_t res[7] = {};\n> +\n> +    mulu64(&lo, &hi, env->active_tc.MPL0, arg1);\n> +    res[0] = lo;\n> +    res[1] = hi;\n> +\n> +    mulu64(&lo, &hi, env->active_tc.MPL1, arg1);\n> +    octeon_addc(res, 7, lo, 1);\n> +    octeon_addc(res, 7, hi, 2);\n> +\n> +    mulu64(&lo, &hi, env->active_tc.MPL2, arg1);\n> +    octeon_addc(res, 7, lo, 2);\n> +    octeon_addc(res, 7, hi, 3);\n> +\n> +    mulu64(&lo, &hi, env->active_tc.MPL3, arg1);\n> +    octeon_addc(res, 7, lo, 3);\n> +    octeon_addc(res, 7, hi, 4);\n> +\n> +    mulu64(&lo, &hi, env->active_tc.MPL4, arg1);\n> +    octeon_addc(res, 7, lo, 4);\n> +    octeon_addc(res, 7, hi, 5);\n> +\n> +    mulu64(&lo, &hi, env->active_tc.MPL5, arg1);\n> +    octeon_addc(res, 7, lo, 5);\n> +    octeon_addc(res, 7, hi, 6);\n> +\n> +    octeon_addc(res, 7, arg2, 0);\n> +    octeon_addc(res, 7, env->active_tc.P0, 0);\n> +    octeon_addc(res, 7, env->active_tc.P1, 1);\n> +    octeon_addc(res, 7, env->active_tc.P2, 2);\n> +    octeon_addc(res, 7, env->active_tc.P3, 3);\n> +    octeon_addc(res, 7, env->active_tc.P4, 4);\n> +    octeon_addc(res, 7, env->active_tc.P5, 5);\n> +\n> +    env->active_tc.P0 = res[1];\n> +    env->active_tc.P1 = res[2];\n> +    env->active_tc.P2 = res[3];\n> +    env->active_tc.P3 = res[4];\n> +    env->active_tc.P4 = res[5];\n> +    env->active_tc.P5 = res[6];\n> +    return res[0];\n> +}\n> +\n>   /* these crc32 functions are based on target/loongarch/tcg/op_helper.c */\n>   target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz)\n>   {","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=bNxZZY16;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4ftzRR16Jhz1xtJ\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 13 Apr 2026 04:22:41 +1000 (AEST)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wBzRb-0007fD-VC; Sun, 12 Apr 2026 14:22:04 -0400","from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <philmd@linaro.org>) id 1wBzRD-0007bm-Hs\n for qemu-devel@nongnu.org; Sun, 12 Apr 2026 14:21:40 -0400","from mail-wm1-x333.google.com ([2a00:1450:4864:20::333])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <philmd@linaro.org>) id 1wBzR7-00089b-QV\n for qemu-devel@nongnu.org; Sun, 12 Apr 2026 14:21:37 -0400","by mail-wm1-x333.google.com with SMTP id\n 5b1f17b1804b1-488a041eae5so26026355e9.1\n for <qemu-devel@nongnu.org>; Sun, 12 Apr 2026 11:21:33 -0700 (PDT)","from [192.168.69.228] (88-187-86-199.subs.proxad.net.\n [88.187.86.199]) by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-488d681edd2sm77324035e9.18.2026.04.12.11.21.29\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Sun, 12 Apr 2026 11:21:30 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1776018091; x=1776622891; darn=nongnu.org;\n h=content-transfer-encoding:in-reply-to:from:references:cc:to\n :content-language:subject:user-agent:mime-version:date:message-id\n :from:to:cc:subject:date:message-id:reply-to;\n bh=cniVNRKYRg9c0G89AiMo8OFsBMp43vw+zrHz9yXn0W4=;\n b=bNxZZY16GVpp8875xpeTBq5qD6eUAGLS8cNss3vL84cjKPffBlIkG0BaNQVe+z9T1h\n cqSrULdcpnbgK50gKZ0yi3oZD138Bkh9eT/I8fLp18Nj497532YKETtj0ALktdM1WEKW\n N44Bbj6bO1ouJI6Xf5Mh+RtO8RNQ9e4/dO9ArCvMwA18A24G1EYAnBeb+5SanPKrPwZf\n s2/+O2dovZEkFpeKY0yGrFssOruDpKMvyw/nCFx7RK9Mva3d80YjVeEiMhA81+AY9/Yz\n uSjeQ0X8gWwH+WpDGy+Btk956uFBIb+N0lj4g1CWS1Gomp0/5Z/Hr8GQSe4lOH/pjjK/\n y5lw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776018091; x=1776622891;\n h=content-transfer-encoding:in-reply-to:from:references:cc:to\n :content-language:subject:user-agent:mime-version:date:message-id\n :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id\n :reply-to;\n bh=cniVNRKYRg9c0G89AiMo8OFsBMp43vw+zrHz9yXn0W4=;\n b=dT5pKqvn1Qw/gl0z6594N+rm2FlYf9yTOAZm8SmJlj8fpIEksMmYNiriWvsrBv4pVq\n n+w2AZ23pQqaP6mwFQ8imXUfWj6ADoDQLuqnDURSDnYD310UMy/R5sOaEKFoEishDMvM\n yrAId2FMGDHeXxyeKYMG6v3FNp4fiwqYlL3AXTMOyWxKhdO6yA0l32wNZ0Fwv49CQxzR\n R7xyBAEyg4qx5tw6FpOsZrhMjOu2GnMbTJsKmMP4zHGKSW3fi/oyqGafGeWOUdZ8JkFR\n BPtzQDeKSCTDxMug6ddhehrxXClOFbFm2o2+FAMmI6o7LvDmYMzDxr9KJDrw3zvSPtFh\n EMfw==","X-Forwarded-Encrypted":"i=1;\n AJvYcCWO85gT+1uNqgo8sIzNa/0JbKm0hAs4MwMOOpKtqSE3lRUQ79bpb+TXIDe0G+D3bk1WFo/Q5QJNefXm@nongnu.org","X-Gm-Message-State":"AOJu0Yzb45G2JtXxRQxlrA44ir8TBdVMOeZ8C/FsVgygOGpKtJA4GJ8r\n F30WuHN0+DfhmApwh3yhB48qK+JuJagF+aZAf5UMDIcs1ovxCU7V7Bq+lfXU4UJKltA=","X-Gm-Gg":"AeBDietW2HaP+vz0tL/QuMbQPjTQAW3EgGVhsClfSWxxU5ho0eKY+hyDcRJZIeDhIHq\n MUAeUX1Py4X23QTx7t6ewl9FAsUhiC8WIZYmRLzItN/XqIyMD7NZgNTNWC1RQXTdtx8hMX4yhJP\n IPL8vK5psuU0eR25Wb5BeDew+BpqGMcwbC3ZY1pUw2m7RaVZMvMPA67armL3FXsbr5YbhZLPTZe\n 7AkKWcys/dc/NojhndkBrQxOg8vCuqSJsYIuk6TGqigXyVqK7PJQVW9EV5cdoQZUXVVNBo1mKHt\n 2iNEegkWx87yGWMMl+AxtvbwBv3qggSHBGY/ug2WGsBaFXPdp+RomQApAHn9EJVYhZgyws493UG\n YBIF91JKAeum/nveypqcdfO3gXcanE7xjdwVkikGWFJQsJ22QhE71iPtnCU7otjt8b6ARblYw3m\n PLO9BGw0q2GJXaO8jwmRaQWS6vfJ8X1QjFRAARxCRPaffUEEmKwR1KHQXfljhZzx9LTw==","X-Received":"by 2002:a05:600c:8883:b0:488:b87b:3052 with SMTP id\n 5b1f17b1804b1-488d689b400mr106098845e9.29.1776018091253;\n Sun, 12 Apr 2026 11:21:31 -0700 (PDT)","Message-ID":"<b78cb17a-65fe-4394-8d62-8caa3447065b@linaro.org>","Date":"Sun, 12 Apr 2026 20:21:29 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH 2/9] target/mips: add Octeon arithmetic and memory\n instructions","Content-Language":"en-US","To":"James Hilliard <james.hilliard1@gmail.com>, qemu-devel@nongnu.org","Cc":"Laurent Vivier <laurent@vivier.eu>,\n Pierrick Bouvier <pierrick.bouvier@linaro.org>,\n Aurelien Jarno <aurelien@aurel32.net>, Jiaxun Yang\n <jiaxun.yang@flygoat.com>, Aleksandar Rikalo <arikalo@gmail.com>,\n Huacai Chen <chenhuacai@kernel.org>, owl <owl129@126.com>","References":"<20260411070637.72421-1-james.hilliard1@gmail.com>\n <20260411070637.72421-2-james.hilliard1@gmail.com>","From":"=?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= <philmd@linaro.org>","In-Reply-To":"<20260411070637.72421-2-james.hilliard1@gmail.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","Received-SPF":"pass client-ip=2a00:1450:4864:20::333;\n envelope-from=philmd@linaro.org; helo=mail-wm1-x333.google.com","X-Spam_score_int":"-20","X-Spam_score":"-2.1","X-Spam_bar":"--","X-Spam_report":"(-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=ham autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"qemu development <qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"}}]