@samitouri / QOSamiQemu / commits / 020bef96fa

target/mips: add Octeon multiplier state

Add per-thread Octeon multiplier state for the MPL and P limb banks used by the VMULU/VMM0/V3MULU instruction family. Octeon3 extends the older MPL0-MPL2/P0-P2 state with high lanes MPL3-MPL5/P3-P5, programmed by the two-source MTM/MTP forms. Represent both banks as uint64_t arrays so the TC state matches the architected 64-bit limb layout used by Octeon68XX user-mode code. Expose MPL/P as global TCG variables so the multiplier translators can expand inline without helper calls. Migrate the multiplier registers in an Octeon-only subsection so non-Octeon CPU models do not grow migration state. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@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-18-philmd@linaro.org>

James Hilliard committed May 8, 2026 at 09:12 UTC 020bef96fae422e468b7883726d5f796b46309d9
4 files changed +65
target/mips/cpu.h
+12
@@ -459,6 +459,14 @@ typedef struct mips_def_t mips_def_t;
459
460
461 typedef struct TCState TCState;
462 +
463 +/*
464 + * Octeon3 adds a second bank of multiplier/product limbs used by the
465 + * two-source MTM/MTP forms: MPL0..2/P0..2 from rs and MPL3..5/P3..5 from rt.
466 + */
467 +#define OCTEON_MULTIPLIER_LANES 3
468 +#define OCTEON_MULTIPLIER_REGS (2 * OCTEON_MULTIPLIER_LANES)
469 +
470 struct TCState {
471 target_ulong gpr[32];
472 #if defined(TARGET_MIPS64)
@@ -497,6 +505,10 @@ struct TCState {
505 target_ulong CP0_TCScheFBack;
506 int32_t CP0_Debug_tcstatus;
507 target_ulong CP0_UserLocal;
508 + struct {
509 + uint64_t MPL[OCTEON_MULTIPLIER_REGS];
510 + uint64_t P[OCTEON_MULTIPLIER_REGS];
511 + } octeon;
512
513 int32_t msacsr;
514
target/mips/system/machine.c
+33
@@ -120,6 +120,17 @@ static const VMStateDescription vmstate_inactive_tc = {
120 .fields = vmstate_tc_fields
121 };
122
123 +static const VMStateDescription vmstate_octeon_multiplier_tc = {
124 + .name = "cpu/tc/octeon_multiplier",
125 + .version_id = 1,
126 + .minimum_version_id = 1,
127 + .fields = (const VMStateField[]) {
128 + VMSTATE_UINT64_ARRAY(octeon.MPL, TCState, OCTEON_MULTIPLIER_REGS),
129 + VMSTATE_UINT64_ARRAY(octeon.P, TCState, OCTEON_MULTIPLIER_REGS),
130 + VMSTATE_END_OF_LIST()
131 + }
132 +};
133 +
134 /* MVP state */
135
136 static const VMStateDescription vmstate_mvp = {
@@ -247,6 +258,27 @@ static const VMStateDescription mips_vmstate_timer = {
258 }
259 };
260
261 +static bool mips_octeon_needed(void *opaque)
262 +{
263 + MIPSCPU *cpu = opaque;
264 +
265 + return cpu->env.insn_flags & INSN_OCTEON;
266 +}
267 +
268 +static const VMStateDescription mips_vmstate_octeon_multiplier = {
269 + .name = "cpu/octeon_multiplier",
270 + .version_id = 1,
271 + .minimum_version_id = 1,
272 + .needed = mips_octeon_needed,
273 + .fields = (const VMStateField[]) {
274 + VMSTATE_STRUCT(env.active_tc, MIPSCPU, 1,
275 + vmstate_octeon_multiplier_tc, TCState),
276 + VMSTATE_STRUCT_ARRAY(env.tcs, MIPSCPU, MIPS_SHADOW_SET_MAX, 1,
277 + vmstate_octeon_multiplier_tc, TCState),
278 + VMSTATE_END_OF_LIST()
279 + }
280 +};
281 +
282 const VMStateDescription vmstate_mips_cpu = {
283 .name = "cpu",
284 .version_id = 21,
@@ -363,6 +395,7 @@ const VMStateDescription vmstate_mips_cpu = {
395 },
396 .subsections = (const VMStateDescription * const []) {
397 &mips_vmstate_timer,
398 + &mips_vmstate_octeon_multiplier,
399 NULL
400 }
401 };
target/mips/tcg/translate.c
+18
@@ -1179,6 +1179,8 @@ static TCGv cpu_lladdr, cpu_llval;
1179 static TCGv_i32 hflags;
1180 TCGv_i32 fpu_fcr0, fpu_fcr31;
1181 TCGv_i64 fpu_f64[32];
1182 +TCGv_i64 oct_mpl[OCTEON_MULTIPLIER_REGS];
1183 +TCGv_i64 oct_p[OCTEON_MULTIPLIER_REGS];
1184
1185 static const char regnames_HI[][4] = {
1186 "HI0", "HI1", "HI2", "HI3",
@@ -15276,6 +15278,22 @@ void mips_tcg_init(void)
15278 active_tc.gpr_hi[i]),
15279 rname);
15280 }
15281 +
15282 + for (unsigned i = 0; i < OCTEON_MULTIPLIER_REGS; ++i) {
15283 + static const char mpl_names[OCTEON_MULTIPLIER_REGS][5] = {
15284 + "MPL0", "MPL1", "MPL2", "MPL3", "MPL4", "MPL5",
15285 + };
15286 + static const char p_names[OCTEON_MULTIPLIER_REGS][3] = {
15287 + "P0", "P1", "P2", "P3", "P4", "P5",
15288 + };
15289 +
15290 + oct_mpl[i] = tcg_global_mem_new_i64(
15291 + tcg_env, offsetof(CPUMIPSState, active_tc.octeon.MPL[i]),
15292 + mpl_names[i]);
15293 + oct_p[i] = tcg_global_mem_new_i64(
15294 + tcg_env, offsetof(CPUMIPSState, active_tc.octeon.P[i]),
15295 + p_names[i]);
15296 + }
15297 #endif /* !TARGET_MIPS64 */
15298 for (unsigned i = 0; i < 32; i++) {
15299 int off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[0]);
target/mips/tcg/translate.h
+2
@@ -189,6 +189,8 @@ void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz, int crc32c);
189 extern TCGv cpu_gpr[32], cpu_PC;
190 #if defined(TARGET_MIPS64)
191 extern TCGv_i64 cpu_gpr_hi[32];
192 +extern TCGv_i64 oct_mpl[OCTEON_MULTIPLIER_REGS];
193 +extern TCGv_i64 oct_p[OCTEON_MULTIPLIER_REGS];
194 #endif
195 extern TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC];
196 extern TCGv_i32 fpu_fcr0, fpu_fcr31;