{"id":2222281,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2222281/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20260411070637.72421-2-james.hilliard1@gmail.com/","project":{"id":14,"url":"http://patchwork.ozlabs.org/api/1.1/projects/14/?format=json","name":"QEMU Development","link_name":"qemu-devel","list_id":"qemu-devel.nongnu.org","list_email":"qemu-devel@nongnu.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260411070637.72421-2-james.hilliard1@gmail.com>","date":"2026-04-11T07:06:28","name":"[2/9] target/mips: add Octeon arithmetic and memory instructions","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"89786b0c40e2053b12e1f9f691d25241c346083e","submitter":{"id":66301,"url":"http://patchwork.ozlabs.org/api/1.1/people/66301/?format=json","name":"James Hilliard","email":"james.hilliard1@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20260411070637.72421-2-james.hilliard1@gmail.com/mbox/","series":[{"id":499531,"url":"http://patchwork.ozlabs.org/api/1.1/series/499531/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/list/?series=499531","date":"2026-04-11T07:06:33","name":"[1/9] linux-user/mips, target/mips: honor MIPS_FIXADE for unaligned accesses","version":1,"mbox":"http://patchwork.ozlabs.org/series/499531/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2222281/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2222281/checks/","tags":{},"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=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=h/U+5/4n;\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=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists.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 4ft4W93Yfvz1yGb\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 11 Apr 2026 17:07:47 +1000 (AEST)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wBSQp-0001ZR-7C; Sat, 11 Apr 2026 03:07:03 -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 <james.hilliard1@gmail.com>)\n id 1wBSQn-0001ZC-8E\n for qemu-devel@nongnu.org; Sat, 11 Apr 2026 03:07:01 -0400","from mail-oi1-x233.google.com ([2607:f8b0:4864:20::233])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <james.hilliard1@gmail.com>)\n id 1wBSQk-0000zd-QQ\n for qemu-devel@nongnu.org; Sat, 11 Apr 2026 03:07:01 -0400","by mail-oi1-x233.google.com with SMTP id\n 5614622812f47-46fc5b8a06bso1708971b6e.0\n for <qemu-devel@nongnu.org>; Sat, 11 Apr 2026 00:06:58 -0700 (PDT)","from Mac.localdomain (71-218-253-186.hlrn.qwest.net.\n [71.218.253.186]) by smtp.gmail.com with ESMTPSA id\n 5614622812f47-478a0f1e841sm2651091b6e.5.2026.04.11.00.06.56\n (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);\n Sat, 11 Apr 2026 00:06:56 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1775891217; x=1776496017; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=D821JP+WdIGQ/cxBmM78QDGbBEU9Ly0BkowSv5N3X6E=;\n b=h/U+5/4nGmz18AD4oZb7Hkv6EHLWqvTl85EcQXeRfus+/eqFqVmIRi8JVpw6QpWADl\n UkEPwYPNPmWr0Dz7u27iuY5gP6+qtpNQgJNaOj2eYAK8qQl4y4hGyxeRs4Y6LrMelXIf\n sSOOHRIfVAy3CYgXz4jZqNBITZxw3xejtae3a5nn5aKUdVRmr/wvWOfgogt4ET0jFwFq\n QCJD9baNWg2/XLtjuw5Y1W850LpNP7aovfFpTrFk48LdNtIhK86cs3XMB/2aWnL5zt4K\n 8onfvKZCBrQke5mui+bJMT4ySy4KvVsn9v2nwoTPus88JMAG2jp6DgCoYy213wH5XdHR\n rVoQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775891217; x=1776496017;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=D821JP+WdIGQ/cxBmM78QDGbBEU9Ly0BkowSv5N3X6E=;\n b=B0os/ajjHC3D9/gUHX03NIbKK9mJyfHTJGVnDzsydZQ+WFb+s6LS9MaB7coe6UhtZ4\n f5uKG3gcOTk0QTadE+iMcUHV+iomJQuyaDw/Ha8qYDHauCEB51aV3XZDXM8mgahBpd4+\n kbBEcB43mfbx6WiDhtgJDnzwwBeK2IvQo5k851CI4mIvxOeATZS/zytY41CtWkonpBlG\n Hakwzjexhji6YfqxPwaec4fFmTznQDFLY4Lpw9Zc/YNPmewVAMyvFgi93hsrpQiDDHJb\n n/Xl8gjUXzj4A57R1a0aFcJHduxLKqhFrsf76Zmkg7FjqxTMhJPOoo26Oi3P0qyvBm01\n f8fA==","X-Gm-Message-State":"AOJu0YzOjnxhfxfo0wq2Fs7W3n1kWSCwYz390cMjzayMmCNm5Ea8K8E0\n /Z4663uFIjeE3cAVvLma9kgTr/0OXpOzHsAtKqZtmc7mbvK1ix7oGKuTjpLTrpXLqM4=","X-Gm-Gg":"AeBDietN2+EcTkjAseIq5qJKkTdpDflUL0V7Tur4w3dnynZIx6cR9RanCRaECZTrTRc\n lotYd9q9zh29b89x/KRXBZN4r+d006ByYLUfU0VsdBjnXbyFV+Sr7NXu0t94QWhTUx2shre5XLK\n hj87HcDNbm3t4dOL+sypd1PhU6XTVlUf+BTWcyxFcEQXnSN8/pgkvKuAP3mphhSEn6hB8tUif7Z\n Av9fUQ9UehwAEqyytvDxepoJi4yuMihn/Y5qJqaXciXeCCMa4cBXdkKmxesKAWUJMIPz5Td3cAr\n p/MIT2EH3Teakf1Dl6ikIaxM5Z+6eijsQ1VPgARnvVDt8vl0cOxV0KzEJU36n+461pTzPkLXrCw\n 05ajvbNw18Ef1Nv5PTVJVuXi5VtmKGOEU+IV3fXi4kz9DuGRrqVlk8i2+z0SADiO8FKjWT7QCiO\n jY/hzK0o8q+pFo//shUg6hJCaB3sV4rg8TonrVYmGZMb3h5OSgGP8/8dUGHo/pN86QckYvuGIag\n Rq4gQENkP7LFxy7CSh68hRSSe5McICsSvOkFQdnf+Sd5kmrJVQGpY7wU7Onj8EmlBph0RUgDtuB\n g3H0PA==","X-Received":"by 2002:a05:6808:1a26:b0:467:f1e5:a294 with SMTP id\n 5614622812f47-478b64a3867mr2305699b6e.4.1775891217196;\n Sat, 11 Apr 2026 00:06:57 -0700 (PDT)","From":"James Hilliard <james.hilliard1@gmail.com>","To":"qemu-devel@nongnu.org","Cc":"James Hilliard <james.hilliard1@gmail.com>,\n Laurent Vivier <laurent@vivier.eu>,\n Pierrick Bouvier <pierrick.bouvier@linaro.org>, =?utf-8?q?Philippe_Mathieu-?=\n\t=?utf-8?q?Daud=C3=A9?= <philmd@linaro.org>,\n Aurelien Jarno <aurelien@aurel32.net>, Jiaxun Yang <jiaxun.yang@flygoat.com>,\n Aleksandar Rikalo <arikalo@gmail.com>, Huacai Chen <chenhuacai@kernel.org>","Subject":"[PATCH 2/9] target/mips: add Octeon arithmetic and memory\n instructions","Date":"Sat, 11 Apr 2026 01:06:28 -0600","Message-ID":"<20260411070637.72421-2-james.hilliard1@gmail.com>","X-Mailer":"git-send-email 2.53.0","In-Reply-To":"<20260411070637.72421-1-james.hilliard1@gmail.com>","References":"<20260411070637.72421-1-james.hilliard1@gmail.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Received-SPF":"pass client-ip=2607:f8b0:4864:20::233;\n envelope-from=james.hilliard1@gmail.com; helo=mail-oi1-x233.google.com","X-Spam_score_int":"-17","X-Spam_score":"-1.8","X-Spam_bar":"-","X-Spam_report":"(-1.8 / 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 FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001,\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"},"content":"Octeon CPUs define additional integer, memory, and multiply operations\nbeyond the base MIPS64 ISA. Add the missing decode and helper support\nfor the remaining regular Octeon instructions used by existing user-mode\nworkloads.\n\nThis covers the indexed unaligned load/store forms, cache block zero\noperations, the Octeon multiply family, population count handling, and\nrelated arithmetic and memory operations in the translator and helper\nlayer.\n\nSigned-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(-)","diff":"diff --git a/target/mips/cpu-defs.c.inc b/target/mips/cpu-defs.c.inc\nindex 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,\ndiff --git a/target/mips/cpu.h b/target/mips/cpu.h\nindex 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 \n     int32_t msacsr;\n \ndiff --git a/target/mips/helper.h b/target/mips/helper.h\nindex 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)\ndiff --git a/target/mips/system/machine.c b/target/mips/system/machine.c\nindex 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 };\ndiff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode\nindex 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\ndiff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c\nindex 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         /* 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         /* 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     }\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+\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+TRANS(VMULU, trans_vmul, gen_helper_octeon_vmulu);\n+TRANS(V3MULU, trans_vmul, gen_helper_octeon_v3mulu);\ndiff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c\nindex 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+{\n+    uint64_t lo, hi;\n+    uint64_t res[3] = {};\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, 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+{\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 {\n","prefixes":["2/9"]}