target/mips: add Octeon V3MULU instruction
V3MULU extends VMULU across the full Octeon3 multiplier state, adding rt and queued partial products. Return the low result while shifting the remaining accumulated limbs back into P[0] through P[5]. 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> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20260520172313.23777-23-philmd@linaro.org>
James Hilliard committed
May 8, 2026 at 10:56 UTC
76f8ab8aeda5aabde1120a055b2647336275b171
2 files changed
+41
target/mips/tcg/octeon.decode
+1
@@ -57,6 +57,7 @@ MTP2 011100 ..... ..... 00000 00000 001011 @r2
57
58
VMULU 011100 ..... ..... ..... 00000 001111 @r3
59
VMM0 011100 ..... ..... ..... 00000 010000 @r3
60
+V3MULU 011100 ..... ..... ..... 00000 010001 @r3
61
62
&saa base rt
63
@saa ...... base:5 rt:5 ................ &saa
target/mips/tcg/octeon_translate.c
+40
@@ -315,3 +315,43 @@ static bool trans_VMM0(DisasContext *ctx, arg_VMM0 *a)
315
octeon_zero_partial_product_state();
316
return true;
317
}
318
+
319
+static bool trans_V3MULU(DisasContext *ctx, arg_V3MULU *a)
320
+{
321
+ TCGv_i64 x[7], y[7], z[7];
322
+ TCGv_i64 tmp = tcg_temp_new_i64();
323
+
324
+ for (int i = 0; i < 7; ++i) {
325
+ z[i] = tcg_temp_new_i64();
326
+ y[i] = tcg_temp_new_i64();
327
+ }
328
+ memcpy(&x[0], z, 6 * sizeof(TCGv_i64));
329
+ x[6] = tcg_constant_i64(0);
330
+
331
+ /*
332
+ * Z = rs * mpl -- 64x384->448 bit multiply
333
+ * Compute even partial products into X and odd partial products into Y.
334
+ * Include RT into the odd partial products, which are 0 in bits [63:0].
335
+ */
336
+ gen_load_gpr(tmp, a->rs);
337
+ gen_load_gpr(y[0], a->rt);
338
+ for (int i = 0; i < 6; i += 2) {
339
+ tcg_gen_mulu2_i64(x[i + 0], x[i + 1], tmp, oct_mpl[i]);
340
+ tcg_gen_mulu2_i64(y[i + 1], y[i + 2], tmp, oct_mpl[i + 1]);
341
+ }
342
+
343
+ /* Sum even and odd to produce final product, plus rt. */
344
+ tcg_gen_addN_i64(7, z, x, y);
345
+
346
+ /* X == (0 : p5 : p4 : p3 : p2 : p1 : p0) -- x[6] is still 0 */
347
+ memcpy(&x[0], oct_p, 6 * sizeof(TCGv_i64));
348
+
349
+ /* Y == (p5 : p4 : p3 : p2 : p1 : p0 : tmp) */
350
+ memcpy(&y[1], oct_p, 6 * sizeof(TCGv_i64));
351
+ y[0] = tmp;
352
+
353
+ /* (p* : rd) = (0 : p*) + (rs * mpl + rt) */
354
+ tcg_gen_addN_i64(7, y, x, z);
355
+ gen_store_gpr(tmp, a->rd);
356
+ return true;
357
+}