Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2221600/?format=api
{ "id": 2221600, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2221600/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260409220614.65558-6-lucaaamaral@gmail.com/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/1.1/projects/14/?format=api", "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": "<20260409220614.65558-6-lucaaamaral@gmail.com>", "date": "2026-04-09T22:06:13", "name": "[v6,5/6] target/arm/emulate: add atomic, compare-and-swap, and PAC load", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "a8b317d7e940f171f2e59fae200d36d88d0065f6", "submitter": { "id": 92822, "url": "http://patchwork.ozlabs.org/api/1.1/people/92822/?format=api", "name": "Lucas Amaral", "email": "lucaaamaral@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260409220614.65558-6-lucaaamaral@gmail.com/mbox/", "series": [ { "id": 499364, "url": "http://patchwork.ozlabs.org/api/1.1/series/499364/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=499364", "date": "2026-04-09T22:06:10", "name": "target/arm: ISV=0 data abort emulation library", "version": 6, "mbox": "http://patchwork.ozlabs.org/series/499364/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2221600/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2221600/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=EpK1SovZ;\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 4fsDZr57Whz1yCv\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 10 Apr 2026 08:08:04 +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 1wAxWR-0008Go-OR; Thu, 09 Apr 2026 18:06:47 -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 <lucaaamaral@gmail.com>)\n id 1wAxWP-0008Ar-Jh\n for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:45 -0400", "from mail-dy1-x132d.google.com ([2607:f8b0:4864:20::132d])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <lucaaamaral@gmail.com>)\n id 1wAxWN-0000cl-Cz\n for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:45 -0400", "by mail-dy1-x132d.google.com with SMTP id\n 5a478bee46e88-2ba9c484e5eso1507649eec.1\n for <qemu-devel@nongnu.org>; Thu, 09 Apr 2026 15:06:43 -0700 (PDT)", "from localhost.localdomain ([2804:7f4:c030:bb40:195d:78fd:ecba:d45])\n by smtp.gmail.com with ESMTPSA id\n 5a478bee46e88-2d561bde68bsm1534567eec.17.2026.04.09.15.06.38\n (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);\n Thu, 09 Apr 2026 15:06:41 -0700 (PDT)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1775772402; x=1776377202; 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=lbIyOfnciDg6afzmMw7/atMx/iFETQJzz2oWEz1fQAg=;\n b=EpK1SovZZZV0NGDNHV7/k0vCsQOSGkF34dwzsjVpzbYyLY3GobLQ98MGMLuaHYgEse\n rv7TrJWGKsgwX8J2Pi+DaE3HQoPXD0qQj56VhIHwZ5s+Je2H1yhdft46tKBZCELdgSYU\n KLBuH48vV6DR+8U/ytCyPMJThSPBdP4vdA7wfab6pRc2Yb7U71cQCJWGzcg4y2JS9Akr\n nr8omoHStdqx21AKvo7ccdY8sBmIy9H4962yifSaqgYDsnsGrWpCREtcyqptL1OB/Owm\n 1JmEA5TG4zHDC8e6VOq49GRRMSuStl3RxhxRl1mFRhv+AJ6Es3HT7pQJwLsiHtRDoq19\n h38Q==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775772402; x=1776377202;\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=lbIyOfnciDg6afzmMw7/atMx/iFETQJzz2oWEz1fQAg=;\n b=ciA7McVYqI2BLqhhidv53WyeKRvrVBpoeQu9fDW9Irxw8iz0qVt0fu3plR5z6jRmqW\n 6rZGHp15g7yw6pdNkDjfPDw42CeK2SRRNzbq7MlRkoqV20bry4uBKWCS8xGwIpRms90W\n zoBAl4BraKx7B7pxBQ1qJ4Htb+lIdLXanvugp9OkbnquBQvqwM8lflnRRO/1gIORviIl\n RgbJ9EI+4JkchenJ1aF0mtOoLCay6BIcWsty1micG5pov1HCs7BxlOHirAkJSzaKYc86\n 5NSUL0UCaWAOloEwDL0KUgeTwNJQZSubmxdOS2FO4UN9D7siUMtPYSbhtnWsE4+QG8AH\n KRMQ==", "X-Gm-Message-State": "AOJu0Yw/qZwE81stxzgQdX1NPq4jwhVtwSoHSg9ouOJzki+ytfWSLJag\n 58H5HscD8DwaAmPQccROEAa9Gf+XBkFd+a9qIUGtQOVBBX5oOvGxXbGNc7p9ldgE", "X-Gm-Gg": "AeBDies+QPh4dRSalLDbaeoQ1zAtxOG08oTFoxUv6quQG1jlhqNPJiOpqPia6Qmnai8\n z0DrDIUYVApOWBBeANVzjpZ24zXt/xVf9bhCpHSDGPZoyu3qlNSnY8TPCb3T5O6Bwaxp8dPQtcp\n umRuQap57geA8WyKLSx5RGcof2Pb1GYKmqg+3f52z1uEKsgnxlrInY3GsopM1sON1fHFxEawx4a\n vBI5sJbH9FPD+OPiaRrXAzw8pKwXZyD76S+rP/UelUkCx+Y70g1+nZxFnMsgjiwnrY3k3gLSHuN\n c357YQkaLUlXReJvae3jGCcaQN8icbf0yIiKOSryAUzLD+9fdvnAIDKK9buslmrExuxiEY3kDKF\n aYyQq5xDYShnBMO7vJjvlPU1BIwOsWJDGutq2iSGTeYm58Yh2A4IPUbUedQA4cD1tAqVyqIQ4Eg\n YZgSKZQliiBRZBclehtdl1h+VM0g23S/a7qRkrkbSKYJqhvJ6Af0cTceKcB2mJJ3pWovkJJTdP", "X-Received": "by 2002:a05:693c:3114:b0:2be:fe8:8b0d with SMTP id\n 5a478bee46e88-2d5887a3180mr530792eec.22.1775772401494;\n Thu, 09 Apr 2026 15:06:41 -0700 (PDT)", "From": "Lucas Amaral <lucaaamaral@gmail.com>", "To": "qemu-devel@nongnu.org", "Cc": "qemu-arm@nongnu.org, agraf@csgraf.de, peter.maydell@linaro.org,\n mohamed@unpredictable.fr, alex.bennee@linaro.org,\n richard.henderson@linaro.org, Lucas Amaral <lucaaamaral@gmail.com>", "Subject": "[PATCH v6 5/6] target/arm/emulate: add atomic, compare-and-swap,\n and PAC load", "Date": "Thu, 9 Apr 2026 19:06:13 -0300", "Message-ID": "<20260409220614.65558-6-lucaaamaral@gmail.com>", "X-Mailer": "git-send-email 2.52.0", "In-Reply-To": "<20260409220614.65558-1-lucaaamaral@gmail.com>", "References": "<20260409220614.65558-1-lucaaamaral@gmail.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "Received-SPF": "pass client-ip=2607:f8b0:4864:20::132d;\n envelope-from=lucaaamaral@gmail.com; helo=mail-dy1-x132d.google.com", "X-Spam_score_int": "-20", "X-Spam_score": "-2.1", "X-Spam_bar": "--", "X-Spam_report": "(-2.1 / 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, FREEMAIL_FROM=0.001,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=unavailable 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": "Add emulation for remaining ISV=0 load/store instruction classes.\n\nAtomic memory operations (DDI 0487 C3.3.2):\n - LDADD, LDCLR, LDEOR, LDSET: arithmetic/logic atomics\n - LDSMAX, LDSMIN, LDUMAX, LDUMIN: signed/unsigned min/max\n - SWP: atomic swap\n Non-atomic read-modify-write, sufficient for MMIO where concurrent\n access is not a concern. Acquire/release semantics are ignored.\n\nCompare-and-swap (DDI 0487 C3.3.1):\n - CAS/CASA/CASAL/CASL: single-register compare-and-swap\n - CASP/CASPA/CASPAL/CASPL: register-pair compare-and-swap\n CASP validates even register pairs; odd or r31 returns UNHANDLED.\n\nLoad with PAC (DDI 0487 C6.2.121):\n - LDRAA/LDRAB: pointer-authenticated load, offset/pre-indexed\n Pointer authentication is not emulated (equivalent to auth always\n succeeding), which is correct for MMIO since PAC is a software\n security mechanism, not a memory access semantic.\n\nDecodetree differences from TCG:\n - %ldra_imm extracts the raw S:imm9 field; the handler scales by\n << 3. TCG applies !function=times_8 in the formatter.\n - @ldra uses wildcards for fixed opcode bits that TCG locks down\n (bits 31:30, bit 20, bit 11); the fixed bits are matched by the\n instruction pattern instead.\n - @cas is an explicit format template; TCG uses inline field\n extraction.\n\nCASP uses two explicit decode patterns for the 32/64-bit size\nvariants. LDRA's offset immediate is stored raw in the decode;\nthe handler scales by << 3.\n\nSigned-off-by: Lucas Amaral <lucaaamaral@gmail.com>\n---\n target/arm/emulate/a64-ldst.decode | 45 ++++++\n target/arm/emulate/arm_emulate.c | 233 +++++++++++++++++++++++++++++\n 2 files changed, 278 insertions(+)", "diff": "diff --git a/target/arm/emulate/a64-ldst.decode b/target/arm/emulate/a64-ldst.decode\nindex fadf6fd2..9292bfdf 100644\n--- a/target/arm/emulate/a64-ldst.decode\n+++ b/target/arm/emulate/a64-ldst.decode\n@@ -16,6 +16,16 @@\n # Load/store pair (GPR and SIMD/FP)\n &ldstpair rt2 rt rn imm sz sign w p\n \n+# Atomic memory operations\n+&atomic rs rn rt a r sz\n+\n+# Compare-and-swap\n+&cas rs rn rt sz a r\n+\n+# Load with PAC (LDRAA/LDRAB, FEAT_PAuth)\n+%ldra_imm 22:s1 12:9\n+&ldra rt rn imm m w\n+\n # Load/store register offset\n &ldst rm rn rt sign ext sz opt s\n \n@@ -36,6 +46,15 @@\n # Load/store pair: imm7 is signed, scaled by element size in handler\n @ldstpair .. ... . ... . imm:s7 rt2:5 rn:5 rt:5 &ldstpair\n \n+# Atomics\n+@atomic sz:2 ... . .. a:1 r:1 . rs:5 . ... .. rn:5 rt:5 &atomic\n+\n+# Compare-and-swap: sz extracted by pattern (CAS) or set constant (CASP)\n+@cas .. ...... . a:1 . rs:5 r:1 ..... rn:5 rt:5 &cas\n+\n+# Load with PAC\n+@ldra .. ... . .. m:1 . . ......... w:1 . rn:5 rt:5 &ldra imm=%ldra_imm\n+\n # Load/store register offset\n @ldst .. ... . .. .. . rm:5 opt:3 s:1 .. rn:5 rt:5 &ldst\n \n@@ -241,6 +260,32 @@ STR_v 00 111 1 00 10 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=\n LDR_v sz:2 111 1 00 01 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0\n LDR_v 00 111 1 00 11 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0 sz=4\n \n+### Compare-and-swap\n+\n+# CAS / CASA / CASAL / CASL\n+CAS sz:2 001000 1 . 1 ..... . 11111 ..... ..... @cas\n+\n+# CASP / CASPA / CASPAL / CASPL (pair: Rt,Rt+1 and Rs,Rs+1)\n+CASP 00 001000 0 . 1 ..... . 11111 ..... ..... @cas sz=2\n+CASP 01 001000 0 . 1 ..... . 11111 ..... ..... @cas sz=3\n+\n+### Atomic memory operations\n+\n+LDADD .. 111 0 00 . . 1 ..... 0000 00 ..... ..... @atomic\n+LDCLR .. 111 0 00 . . 1 ..... 0001 00 ..... ..... @atomic\n+LDEOR .. 111 0 00 . . 1 ..... 0010 00 ..... ..... @atomic\n+LDSET .. 111 0 00 . . 1 ..... 0011 00 ..... ..... @atomic\n+LDSMAX .. 111 0 00 . . 1 ..... 0100 00 ..... ..... @atomic\n+LDSMIN .. 111 0 00 . . 1 ..... 0101 00 ..... ..... @atomic\n+LDUMAX .. 111 0 00 . . 1 ..... 0110 00 ..... ..... @atomic\n+LDUMIN .. 111 0 00 . . 1 ..... 0111 00 ..... ..... @atomic\n+SWP .. 111 0 00 . . 1 ..... 1000 00 ..... ..... @atomic\n+\n+### Load with PAC (FEAT_PAuth)\n+\n+# LDRAA (M=0) / LDRAB (M=1), offset (W=0) / pre-indexed (W=1)\n+LDRA 11 111 0 00 . . 1 ......... . 1 ..... ..... @ldra\n+\n ### System instructions — DC cache maintenance\n \n # SYS with CRn=C7 covers all data cache operations (DC CIVAC, CVAC, etc.).\ndiff --git a/target/arm/emulate/arm_emulate.c b/target/arm/emulate/arm_emulate.c\nindex 7f876355..6601c9dc 100644\n--- a/target/arm/emulate/arm_emulate.c\n+++ b/target/arm/emulate/arm_emulate.c\n@@ -547,6 +547,239 @@ static bool trans_LDXP(DisasContext *ctx, arg_stxr *a)\n return true;\n }\n \n+/*\n+ * Atomic memory operations (DDI 0487 C3.3.2)\n+ *\n+ * Non-atomic read-modify-write; sufficient for MMIO.\n+ * Acquire/release semantics ignored (sequentially consistent by design).\n+ */\n+\n+typedef uint64_t (*atomic_op_fn)(uint64_t old, uint64_t operand, int bits);\n+\n+static uint64_t atomic_add(uint64_t old, uint64_t op, int bits)\n+{\n+ return old + op;\n+}\n+\n+static uint64_t atomic_clr(uint64_t old, uint64_t op, int bits)\n+{\n+ return old & ~op;\n+}\n+\n+static uint64_t atomic_eor(uint64_t old, uint64_t op, int bits)\n+{\n+ return old ^ op;\n+}\n+\n+static uint64_t atomic_set(uint64_t old, uint64_t op, int bits)\n+{\n+ return old | op;\n+}\n+\n+static uint64_t atomic_smax(uint64_t old, uint64_t op, int bits)\n+{\n+ int64_t a = sextract64(old, 0, bits);\n+ int64_t b = sextract64(op, 0, bits);\n+ return (a >= b) ? old : op;\n+}\n+\n+static uint64_t atomic_smin(uint64_t old, uint64_t op, int bits)\n+{\n+ int64_t a = sextract64(old, 0, bits);\n+ int64_t b = sextract64(op, 0, bits);\n+ return (a <= b) ? old : op;\n+}\n+\n+static uint64_t atomic_umax(uint64_t old, uint64_t op, int bits)\n+{\n+ uint64_t mask = (bits == 64) ? UINT64_MAX : (1ULL << bits) - 1;\n+ return ((old & mask) >= (op & mask)) ? old : op;\n+}\n+\n+static uint64_t atomic_umin(uint64_t old, uint64_t op, int bits)\n+{\n+ uint64_t mask = (bits == 64) ? UINT64_MAX : (1ULL << bits) - 1;\n+ return ((old & mask) <= (op & mask)) ? old : op;\n+}\n+\n+static bool do_atomic(DisasContext *ctx, arg_atomic *a, atomic_op_fn fn)\n+{\n+ int esize = 1 << a->sz;\n+ int bits = 8 * esize;\n+ uint64_t va = base_read(ctx, a->rn);\n+ uint8_t buf[8];\n+\n+ if (mem_read(ctx, va, buf, esize) != 0) {\n+ return true;\n+ }\n+\n+ uint64_t old = mem_ld(ctx, buf, esize);\n+ uint64_t operand = gpr_read(ctx, a->rs);\n+ uint64_t result = fn(old, operand, bits);\n+\n+ mem_st(ctx, buf, esize, result);\n+ if (mem_write(ctx, va, buf, esize) != 0) {\n+ return true;\n+ }\n+\n+ /* Rt receives the old value (before modification) */\n+ gpr_write(ctx, a->rt, old);\n+ return true;\n+}\n+\n+static bool trans_LDADD(DisasContext *ctx, arg_atomic *a)\n+{\n+ return do_atomic(ctx, a, atomic_add);\n+}\n+\n+static bool trans_LDCLR(DisasContext *ctx, arg_atomic *a)\n+{\n+ return do_atomic(ctx, a, atomic_clr);\n+}\n+\n+static bool trans_LDEOR(DisasContext *ctx, arg_atomic *a)\n+{\n+ return do_atomic(ctx, a, atomic_eor);\n+}\n+\n+static bool trans_LDSET(DisasContext *ctx, arg_atomic *a)\n+{\n+ return do_atomic(ctx, a, atomic_set);\n+}\n+\n+static bool trans_LDSMAX(DisasContext *ctx, arg_atomic *a)\n+{\n+ return do_atomic(ctx, a, atomic_smax);\n+}\n+\n+static bool trans_LDSMIN(DisasContext *ctx, arg_atomic *a)\n+{\n+ return do_atomic(ctx, a, atomic_smin);\n+}\n+\n+static bool trans_LDUMAX(DisasContext *ctx, arg_atomic *a)\n+{\n+ return do_atomic(ctx, a, atomic_umax);\n+}\n+\n+static bool trans_LDUMIN(DisasContext *ctx, arg_atomic *a)\n+{\n+ return do_atomic(ctx, a, atomic_umin);\n+}\n+\n+static bool trans_SWP(DisasContext *ctx, arg_atomic *a)\n+{\n+ int esize = 1 << a->sz;\n+ uint64_t va = base_read(ctx, a->rn);\n+ uint8_t buf[8];\n+\n+ if (mem_read(ctx, va, buf, esize) != 0) {\n+ return true;\n+ }\n+\n+ uint64_t old = mem_ld(ctx, buf, esize);\n+ mem_st(ctx, buf, esize, gpr_read(ctx, a->rs));\n+ if (mem_write(ctx, va, buf, esize) != 0) {\n+ return true;\n+ }\n+\n+ gpr_write(ctx, a->rt, old);\n+ return true;\n+}\n+\n+/* Compare-and-swap: CAS, CASP (DDI 0487 C3.3.1) */\n+\n+static bool trans_CAS(DisasContext *ctx, arg_cas *a)\n+{\n+ int esize = 1 << a->sz;\n+ uint64_t va = base_read(ctx, a->rn);\n+ uint8_t buf[8];\n+\n+ if (mem_read(ctx, va, buf, esize) != 0) {\n+ return true;\n+ }\n+\n+ uint64_t current = mem_ld(ctx, buf, esize);\n+ uint64_t mask = (esize == 8) ? UINT64_MAX : (1ULL << (8 * esize)) - 1;\n+ uint64_t compare = gpr_read(ctx, a->rs) & mask;\n+\n+ if ((current & mask) == compare) {\n+ uint64_t newval = gpr_read(ctx, a->rt) & mask;\n+ mem_st(ctx, buf, esize, newval);\n+ if (mem_write(ctx, va, buf, esize) != 0) {\n+ return true;\n+ }\n+ }\n+\n+ /* Rs receives the old memory value (whether or not swap occurred) */\n+ gpr_write(ctx, a->rs, current);\n+ return true;\n+}\n+\n+/* CASP: compare-and-swap pair (Rs,Rs+1 compared; Rt,Rt+1 stored) */\n+static bool trans_CASP(DisasContext *ctx, arg_cas *a)\n+{\n+ /* CASP requires even register pairs; odd or r31 is UNPREDICTABLE */\n+ if ((a->rs & 1) || a->rs >= 31 || (a->rt & 1) || a->rt >= 31) {\n+ return false;\n+ }\n+\n+ int esize = 1 << a->sz; /* per-register size */\n+ uint64_t va = base_read(ctx, a->rn);\n+ uint8_t buf[16];\n+\n+ if (mem_read(ctx, va, buf, 2 * esize) != 0) {\n+ return true;\n+ }\n+ uint64_t cur1 = mem_ld(ctx, buf, esize);\n+ uint64_t cur2 = mem_ld(ctx, buf + esize, esize);\n+\n+ uint64_t mask = (esize == 8) ? UINT64_MAX : (1ULL << (8 * esize)) - 1;\n+ uint64_t cmp1 = gpr_read(ctx, a->rs) & mask;\n+ uint64_t cmp2 = gpr_read(ctx, a->rs + 1) & mask;\n+\n+ if ((cur1 & mask) == cmp1 && (cur2 & mask) == cmp2) {\n+ uint64_t new1 = gpr_read(ctx, a->rt) & mask;\n+ uint64_t new2 = gpr_read(ctx, a->rt + 1) & mask;\n+ mem_st(ctx, buf, esize, new1);\n+ mem_st(ctx, buf + esize, esize, new2);\n+ if (mem_write(ctx, va, buf, 2 * esize) != 0) {\n+ return true;\n+ }\n+ }\n+\n+ gpr_write(ctx, a->rs, cur1);\n+ gpr_write(ctx, a->rs + 1, cur2);\n+ return true;\n+}\n+\n+/*\n+ * Load with PAC: LDRAA / LDRAB (FEAT_PAuth)\n+ * (DDI 0487 C6.2.121)\n+ *\n+ * Pointer authentication is not emulated -- the base register is used\n+ * directly (equivalent to auth always succeeding).\n+ */\n+\n+static bool trans_LDRA(DisasContext *ctx, arg_ldra *a)\n+{\n+ int64_t offset = (int64_t)a->imm << 3; /* S:imm9, scaled by 8 */\n+ uint64_t base = base_read(ctx, a->rn);\n+ uint64_t va = base + offset; /* auth not emulated */\n+ uint8_t buf[8];\n+\n+ if (mem_read(ctx, va, buf, 8) != 0) {\n+ return true;\n+ }\n+\n+ gpr_write(ctx, a->rt, mem_ld(ctx, buf, 8));\n+\n+ if (a->w) {\n+ base_write(ctx, a->rn, va);\n+ }\n+ return true;\n+}\n+\n /* PRFM, DC cache maintenance -- treated as NOP */\n static bool trans_NOP(DisasContext *ctx, arg_NOP *a)\n {\n", "prefixes": [ "v6", "5/6" ] }