@samitouri / QOSamiQemu / commits / 710be4a712

target/mips: add Octeon QMAC instructions

QMAC.0x and QMACS.0x multiply the selected signed Q15 halfword lane from rs by rt<15:0> and accumulate the Q31 product into the Octeon HI/LO accumulator state. QMAC updates the full 64-bit HI/LO accumulator. QMACS saturates the 32-bit Q31 result in LO and keeps HI<0> as the sticky saturation flag. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: James Hilliard <james.hilliard1@gmail.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> [PMD: Add min32/max32 in trans_QMACS()] Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20260520172313.23777-24-philmd@linaro.org>

James Hilliard committed May 11, 2026 at 12:22 UTC 710be4a71224f8cdecdd0dd69110a8099bc8a3e6
2 files changed +66
target/mips/tcg/octeon.decode
+4
@@ -28,6 +28,8 @@ BBIT 11 set:1 . 10 rs:5 ..... offset:s16 p=%bbit_p
28 # SEQI rt, rs, immediate
29 # SNE rd, rs, rt
30 # SNEI rt, rs, immediate
31 +# QMAC.0x rs, rt
32 +# QMACS.0x rs, rt
33
34 @r3 ...... rs:5 rt:5 rd:5 ..... ......
35 &cmpi rs rt imm
@@ -43,6 +45,8 @@ SEQ 011100 ..... ..... ..... 00000 101010 @r3
45 SNE 011100 ..... ..... ..... 00000 101011 @r3
46 SEQI 011100 rs:5 rt:5 imm:s10 101110 &cmpi
47 SNEI 011100 rs:5 rt:5 imm:s10 101111 &cmpi
48 +QMACS 011100 rs:5 rt:5 00000 000 lane:2 010010
49 +QMAC 011100 rs:5 rt:5 00000 100 lane:2 010010
50
51 &r2 rs rt
52 @r2 ...... rs:5 rt:5 ..... ..... ...... &r2
target/mips/tcg/octeon_translate.c
+62
@@ -355,3 +355,65 @@ static bool trans_V3MULU(DisasContext *ctx, arg_V3MULU *a)
355 gen_store_gpr(tmp, a->rd);
356 return true;
357 }
358 +
359 +static bool trans_QMAC(DisasContext *ctx, arg_QMAC *a)
360 +{
361 + TCGv_i64 t0 = tcg_temp_new_i64();
362 + TCGv_i64 t1 = tcg_temp_new_i64();
363 +
364 + gen_load_gpr(t0, a->rt);
365 + gen_load_gpr(t1, a->rs);
366 +
367 + /* t0 = rt<0> * rs<lane> * 2 */
368 + tcg_gen_ext16s_i64(t0, t0);
369 + tcg_gen_sextract_i64(t1, t1, a->lane * 16, 16);
370 + tcg_gen_mul_i64(t0, t0, t1);
371 + tcg_gen_add_i64(t0, t0, t0);
372 +
373 + /* Saturate -0x8000 * -0x8000 * 2 = 0x80000000 -> 0x7fffffff */
374 + tcg_gen_smin_i64(t0, t0, tcg_constant_i64(INT32_MAX));
375 +
376 + /* HI:LO += t0 */
377 + tcg_gen_concat32_i64(t1, cpu_LO[0], cpu_HI[0]);
378 + tcg_gen_add_i64(t0, t0, t1);
379 + tcg_gen_sextract_i64(cpu_LO[0], t0, 0, 32);
380 + tcg_gen_sextract_i64(cpu_HI[0], t0, 32, 32);
381 + return true;
382 +}
383 +
384 +static bool trans_QMACS(DisasContext *ctx, arg_QMACS *a)
385 +{
386 + TCGv_i64 min32 = tcg_constant_i64(INT32_MIN);
387 + TCGv_i64 max32 = tcg_constant_i64(INT32_MAX);
388 + TCGv_i64 t0 = tcg_temp_new_i64();
389 + TCGv_i64 t1 = tcg_temp_new_i64();
390 +
391 + gen_load_gpr(t0, a->rt);
392 + gen_load_gpr(t1, a->rs);
393 +
394 + /* t0 = rt<0> * rs<lane> * 2 */
395 + tcg_gen_ext16s_i64(t0, t0);
396 + tcg_gen_sextract_i64(t1, t1, a->lane * 16, 16);
397 + tcg_gen_mul_i64(t0, t0, t1);
398 + tcg_gen_add_i64(t0, t0, t0);
399 +
400 + /*
401 + * Saturate -0x8000 * -0x8000 * 2 = 0x80000000 -> 0x7fffffff.
402 + * Accumulate overflow in HI[0].
403 + */
404 + tcg_gen_smin_i64(t1, t0, max32);
405 + tcg_gen_setcond_i64(TCG_COND_NE, t0, t0, t1);
406 + tcg_gen_or_i64(cpu_HI[0], cpu_HI[0], t0);
407 +
408 + /*
409 + * LO = sat32(LO + t0)
410 + * Accumulate overflow in HI[0].
411 + */
412 + tcg_gen_ext32s_i64(t0, cpu_LO[0]);
413 + tcg_gen_add_i64(t0, t0, t1);
414 + tcg_gen_smin_i64(cpu_LO[0], t0, max32);
415 + tcg_gen_smax_i64(cpu_LO[0], cpu_LO[0], min32);
416 + tcg_gen_setcond_i64(TCG_COND_NE, t0, t0, cpu_LO[0]);
417 + tcg_gen_or_i64(cpu_HI[0], cpu_HI[0], t0);
418 + return true;
419 +}