@samitouri / QOSamiQemu / commits / f527390c33

target/mips: add Octeon VMM0 instruction

VMM0 multiplies MPL[0] by rs, adds rt and the queued P[0] partial product, returns the low result, and feeds that result back into MPL[0]. It sets MPL[1] to zero and clears partial products. Include hardware-backed regression coverage for VMM0 MPL1 zeroing. 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> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20260520172313.23777-22-philmd@linaro.org>

James Hilliard committed May 8, 2026 at 10:55 UTC f527390c33031eda5a89351e9b23ffd2306e59d6
3 files changed +72
target/mips/tcg/octeon.decode
+1
@@ -56,6 +56,7 @@ MTP1 011100 ..... ..... 00000 00000 001010 @r2
56 MTP2 011100 ..... ..... 00000 00000 001011 @r2
57
58 VMULU 011100 ..... ..... ..... 00000 001111 @r3
59 +VMM0 011100 ..... ..... ..... 00000 010000 @r3
60
61 &saa base rt
62 @saa ...... base:5 rt:5 ................ &saa
target/mips/tcg/octeon_translate.c
+16
@@ -299,3 +299,19 @@ static bool trans_VMULU(DisasContext *ctx, arg_VMULU *a)
299 gen_store_gpr(tmp, a->rd);
300 return true;
301 }
302 +
303 +static bool trans_VMM0(DisasContext *ctx, arg_VMM0 *a)
304 +{
305 + TCGv_i64 tmp = tcg_temp_new_i64();
306 +
307 + gen_load_gpr(tmp, a->rs);
308 + tcg_gen_mul_i64(oct_mpl[0], oct_mpl[0], tmp);
309 + gen_load_gpr(tmp, a->rt);
310 + tcg_gen_add_i64(oct_mpl[0], oct_mpl[0], tmp);
311 + tcg_gen_add_i64(oct_mpl[0], oct_mpl[0], oct_p[0]);
312 + gen_store_gpr(oct_mpl[0], a->rd);
313 +
314 + tcg_gen_movi_i64(oct_mpl[1], 0);
315 + octeon_zero_partial_product_state();
316 + return true;
317 +}
tests/tcg/mips/user/isa/octeon/octeon-insns.c
+55
@@ -105,6 +105,59 @@ static uint64_t octeon_vmulu(uint64_t mpl0, uint64_t rs, uint64_t rt)
105 return rd;
106 }
107
108 +static uint64_t octeon_vmm0(uint64_t mpl0, uint64_t p0,
109 + uint64_t rs, uint64_t rt)
110 +{
111 + uint64_t rd;
112 +
113 + asm volatile(
114 + "move $8, %[mpl0]\n\t"
115 + "move $9, $0\n\t"
116 + ".word 0x71090008\n\t" /* mtm0 $8, $9 */
117 + "move $8, %[p0]\n\t"
118 + "move $9, $0\n\t"
119 + ".word 0x71090009\n\t" /* mtp0 $8, $9 */
120 + "move $8, %[rs]\n\t"
121 + "move $9, %[rt]\n\t"
122 + ".word 0x71095010\n\t" /* vmm0 $10, $8, $9 */
123 + "move %[rd], $10\n\t"
124 + : [rd] "=r" (rd)
125 + : [mpl0] "r" (mpl0), [p0] "r" (p0),
126 + [rs] "r" (rs), [rt] "r" (rt)
127 + : "$8", "$9", "$10");
128 +
129 + return rd;
130 +}
131 +
132 +static uint64_t octeon_vmm0_zeroes_mpl1(void)
133 +{
134 + uint64_t rd;
135 +
136 + asm volatile(
137 + "move $8, %[mpl0]\n\t"
138 + "move $9, $0\n\t"
139 + ".word 0x71090008\n\t" /* mtm0 $8, $9 */
140 + "move $8, %[mpl1]\n\t"
141 + "move $9, $0\n\t"
142 + ".word 0x7109000c\n\t" /* mtm1 $8, $9 */
143 + "move $8, %[vmm0_rs]\n\t"
144 + "move $9, $0\n\t"
145 + ".word 0x71095010\n\t" /* vmm0 $10, $8, $9 */
146 + "move $8, %[vmulu_rs]\n\t"
147 + "move $9, $0\n\t"
148 + ".word 0x7109500f\n\t" /* vmulu $10, $8, $9 */
149 + "move $8, $0\n\t"
150 + "move $9, $0\n\t"
151 + ".word 0x7109500f\n\t" /* vmulu $10, $8, $9 */
152 + "move %[rd], $10\n\t"
153 + : [rd] "=r" (rd)
154 + : [mpl0] "r" (1ULL), [mpl1] "r" (1ULL),
155 + [vmm0_rs] "r" (2ULL), [vmulu_rs] "r" (1ULL)
156 + : "$8", "$9", "$10");
157 +
158 + return rd;
159 +}
160 +
161 static uint64_t octeon_mtp0_zeroes_p1(void)
162 {
163 uint64_t rd;
@@ -143,6 +196,8 @@ int main(void)
196 assert(octeon_sne(0xabc, 0xabc) == 0);
197 assert(octeon_sne(0xabc, 0xdef) == 1);
198 assert(octeon_vmulu(5, 7, 11) == 46);
199 + assert(octeon_vmm0(5, 13, 7, 11) == 59);
200 + assert(octeon_vmm0_zeroes_mpl1() == 0);
201 assert(octeon_mtp0_zeroes_p1() == 0);
202
203 return 0;