From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6729EC88E5C for ; Wed, 16 Sep 2026 10:02:25 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x6mRp-0008C8-VW; Wed, 16 Sep 2026 06:01:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x6mRc-00086n-3K for qemu-arm@nongnu.org; Wed, 16 Sep 2026 06:00:50 -0400 Received: from qs-2003b-snip6-3.eps.apple.com ([2a01:b747:3006:204::10] helo=outbound.qs.icloud.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x6mRV-0005DP-Lh for qemu-arm@nongnu.org; Wed, 16 Sep 2026 06:00:45 -0400 Received: from outbound.qs.icloud.com (unknown [127.0.0.2]) by p00-icloudmta-asmtp-us-east-2d-100-percent-8 (Postfix) with ESMTPS id C94E618009DA; Wed, 16 Sep 2026 10:00:38 +0000 (UTC) X-ICL-RepId: 01a0a9a9-4854-7311-ab53-abd902c26911 X-ICL-Out-Info: HUtFAUMHWwJACUgBTUQeDx5WFlZNRAJCTQ1OHVwPUhxEDlYCVRcOVk1UF1sMWg5WMEwWQx9SD1sTTRlRAVJFVAIZHldQQgVCAlwcWg5DClAcXFZVHxcZUU0ISxMFUgddTVYNRw9YHlwUFwlAQ14IXh9MHB0OWAYSAE0KDjYGWQVeCVYDQwU2EhRdRUYDRxlXFFAbRwxVB1deXwoTAF4PD0wLSAFbB1IDRghIA10FWhxHCkABWBpfHx1WEFIAUg9yBVcIQQhTAlEEWBpfCBkNQE4ZDEodUlZRBUoMXABoD10dWBFd Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=unpredictable.fr; s=sig1; t=1789552841; x=1792144841; bh=4BwMwrO7JAl69k934i2fO7Es+BH41aFRqji3KVvqW4Y=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:x-icloud-hme; b=p4HnGKIgQ5sn01K1DfzPy1JFPxQxDTCgmrRr3WO1+ncZr2M9y3E3xYYEeiVx1DBHT+2lDE5mwk1G59n05ALeqq1qj8/UNy3wf3eVcEaezytb5Gkhf3K7GQiBgFwuhTs3pdrMnfEPc5kTbrJEmOwTWryt3Oubpkqvv8KYm1MHKJ8gfE05dnKoIRa0JiTo04Y8EN47K0a4H1FFW1sNEtmaKKfibh3DP9ZIEP8BeHut/MlMqU8okBTKD7duWDEahDf7M9qtYk9j6fnvLehMhN8m/0OWrCI8LxTzQNtjhgywY3NCF7kQTU435iGPN9AvZzfIoGu8BkyrscjF+6AA18SIug== mail-alias-created-date: 1752046281608 Received: from localhost.localdomain (unknown [17.57.155.37]) by p00-icloudmta-asmtp-us-east-2d-100-percent-8 (Postfix) with ESMTPSA id 9950C18009EE; Wed, 16 Sep 2026 10:00:36 +0000 (UTC) From: Mohamed Mediouni To: qemu-devel@nongnu.org Cc: "Michael S. Tsirkin" , Roman Bolshakov , Peter Maydell , Peter Xu , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-arm@nongnu.org, Phil Dennis-Jordan , Akihiko Odaki , Mohamed Mediouni , Alexander Graf , Paolo Bonzini , Lucas Amaral Subject: [RFC PATCH v8 03/10] target/arm/emulate: add load/store pair Date: Wed, 16 Sep 2026 12:00:11 +0200 Message-ID: <20260916100021.73825-4-mohamed@unpredictable.fr> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260916100021.73825-1-mohamed@unpredictable.fr> References: <20260916100021.73825-1-mohamed@unpredictable.fr> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Proofpoint-ORIG-GUID: KKqxK7NhA4Y_z0JUTt0UU1B9Me102zy1 X-Proofpoint-GUID: KKqxK7NhA4Y_z0JUTt0UU1B9Me102zy1 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTE2MDEzMCBTYWx0ZWRfX7bjBn+FP5mAy pItdV6pXbFGKGqJKz/p1327SkkCKdqqmovLynVC26nsjFpSL28/559zrq1gexzlgOjfhPW2Grg9 vNpNKbeNOShVUL++lpoHqoUdvw1TH9qyPovOVn33DvKUtE56nIBZ/bwbR0Sk/L4221CoXQt/r4A AT0UDOLD5mN6b1rioSFEZkDuL8gnV3s00hzfgibI2yI5oG4c4gugG/T+mJijf5zbyy97F22Kb1U e2NqarbVTxBJ8dHMiMZRzNhDWTJc5nb3UOJad0fMypc91iL2y6IGOGpSFFKuSHL8sWbZPjg4Qul JZpSxAbNbWUjwlbfFVynx6H9oAYQVaqeTJ/w+QtHU2ZTmRSf+SEg4DqTnzPGlk= X-Authority-Info-Out: v=2.4 cv=Dbcaa/tW c=1 sm=1 tr=0 ts=6aaa68c8 cx=c_apl:c_pps:t_out a=bsP7O+dXZ5uKcj+dsLqiMw==:117 a=bsP7O+dXZ5uKcj+dsLqiMw==:17 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=pGLkceISAAAA:8 a=Id3laG5OJmoZrSkAkcIA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 X-JNJ: AAAAAAABvZ1zU6K/G0kmh3gx9mnSk+GGIEIl9NCggJTGPbK9Kms1dU9gd4nsDQzsPh8hydDcRHFMsDkTn28gB2JUMl2RL68IpeMgMUCSuaSThRI0G9Yywn5yXtcy/KRwGYxtXiD63mLFSXvfXJ2dpNwoIEE9XgsZpZULU/FcT3jvSZ4eYLt6dWCIEZPn2Nn/lEvyrFPBEP1Oh8tbJpC2DpR43yLlB6wVPAOtzy9zlRLlt6S8O7vjgW6B7hcllCBKCdeTZj7HCYnoYmDDFmRa94MmT3HR9axymhyJgmJxw9+4NzLsXoZSfisYlv5ayTmrMFYXIInM7hfqikMYEDRfDzuTyQ7+9wXm3zjKKvHY0QuE57+ulW9iLW/+P89HCY+JMDcfft74NyAy/mKT2NGkItRThhc3bfuJlF/ZR3zJNZbwUQTVGg83Bb70mGTTIJYbHyk9UZwTbiL+OFwtReHlUo5r9NhdKGTZ7GvJBdUSbtU8cOdjsSzJwpCeapPlfIY3xDW5tZVXLl6q5DqaSSLV3FKSe5Cb/NpPRSTAo9fpXqaHQ/Elc6N+2uBr8TxkrhBbzOCGR7QoNDqw1FXLH6d8DN/bjYjkBzKYhUmOVwvFpmes+mS8WZ5AYF0PINJeq4MzJBai8xC91g3n7Kfc4Ws7pswqoIkA5GFaCXeo+dmS44q9+iESsRa5BFrrXCgIqkFazgBLIgkHiWUHE0fbagvVucm5NJnv7vA5BVmJR3daKhz1BYqUC7INBwvGCIhI1NTmEWYPQ+1/zfi+OH2e3TRIP+W1CxhDUPNeTC0flQZgbylGcCUl53CElfkZHXwjJpU4PjtGtofVrGCBfdRtdw== Received-SPF: pass client-ip=2a01:b747:3006:204::10; envelope-from=mohamed@unpredictable.fr; helo=outbound.qs.icloud.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, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-arm@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-arm-bounces+qemu-arm=archiver.kernel.org@nongnu.org Sender: qemu-arm-bounces+qemu-arm=archiver.kernel.org@nongnu.org From: Lucas Amaral Add emulation for load/store pair instructions (DDI 0487 C3.3.14 -- C3.3.16). All addressing modes are covered: non-temporal (STNP/LDNP), post-indexed, signed offset, and pre-indexed. Instruction coverage: - STP/LDP (GPR): 32/64-bit pairs, all addressing modes - STP/LDP (SIMD/FP): 32/64/128-bit pairs, all addressing modes - LDPSW: sign-extending 32-bit pair load - STGP: store allocation tag pair (tag operation is NOP for MMIO) Signed-off-by: Lucas Amaral --- target/arm/emulate/a64-ldst.decode | 68 ++++++++++++++++++ target/arm/emulate/arm_emulate.c | 111 +++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/target/arm/emulate/a64-ldst.decode b/target/arm/emulate/a64-ldst.decode index af6babe14a..f3de3f86cb 100644 --- a/target/arm/emulate/a64-ldst.decode +++ b/target/arm/emulate/a64-ldst.decode @@ -10,6 +10,9 @@ # 'u' flag: 0 = 9-bit signed immediate (byte offset), 1 = 12-bit unsigned (needs << sz) &ldst_imm rt rn imm sz sign w p unpriv ext u +# Load/store pair (GPR and SIMD/FP) +&ldstpair rt2 rt rn imm sz sign w p + # Load/store register offset &ldst rm rn rt sign ext sz opt s @@ -24,6 +27,9 @@ # Load/store unsigned offset (12-bit, handler scales by << sz) @ldst_uimm .. ... . .. .. imm:12 rn:5 rt:5 &ldst_imm u=1 unpriv=0 p=0 w=0 +# Load/store pair: imm7 is signed, scaled by element size in handler +@ldstpair .. ... . ... . imm:s7 rt2:5 rn:5 rt:5 &ldstpair + # Load/store register offset @ldst .. ... . .. .. . rm:5 opt:3 s:1 .. rn:5 rt:5 &ldst @@ -128,6 +134,68 @@ STR_v_i 00 111 1 01 10 ............ ..... ..... @ldst_uimm sign= LDR_v_i sz:2 111 1 01 01 ............ ..... ..... @ldst_uimm sign=0 ext=0 LDR_v_i 00 111 1 01 11 ............ ..... ..... @ldst_uimm sign=0 ext=0 sz=4 +### Load/store pair — non-temporal (STNP/LDNP) + +# STNP/LDNP: offset only, no writeback. Non-temporal hint ignored. +STP 00 101 0 000 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0 +LDP 00 101 0 000 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0 +STP 10 101 0 000 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +LDP 10 101 0 000 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +STP_v 00 101 1 000 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0 +LDP_v 00 101 1 000 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0 +STP_v 01 101 1 000 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +LDP_v 01 101 1 000 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +STP_v 10 101 1 000 0 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=0 +LDP_v 10 101 1 000 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=0 + +### Load/store pair — post-indexed + +STP 00 101 0 001 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=1 w=1 +LDP 00 101 0 001 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=1 w=1 +LDP 01 101 0 001 1 ....... ..... ..... ..... @ldstpair sz=2 sign=1 p=1 w=1 +STP 10 101 0 001 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1 +LDP 10 101 0 001 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1 +STP_v 00 101 1 001 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=1 w=1 +LDP_v 00 101 1 001 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=1 w=1 +STP_v 01 101 1 001 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1 +LDP_v 01 101 1 001 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1 +STP_v 10 101 1 001 0 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=1 w=1 +LDP_v 10 101 1 001 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=1 w=1 + +### Load/store pair — signed offset + +STP 00 101 0 010 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0 +LDP 00 101 0 010 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0 +LDP 01 101 0 010 1 ....... ..... ..... ..... @ldstpair sz=2 sign=1 p=0 w=0 +STP 10 101 0 010 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +LDP 10 101 0 010 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +STP_v 00 101 1 010 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0 +LDP_v 00 101 1 010 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0 +STP_v 01 101 1 010 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +LDP_v 01 101 1 010 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +STP_v 10 101 1 010 0 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=0 +LDP_v 10 101 1 010 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=0 + +### Load/store pair — pre-indexed + +STP 00 101 0 011 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=1 +LDP 00 101 0 011 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=1 +LDP 01 101 0 011 1 ....... ..... ..... ..... @ldstpair sz=2 sign=1 p=0 w=1 +STP 10 101 0 011 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1 +LDP 10 101 0 011 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1 +STP_v 00 101 1 011 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=1 +LDP_v 00 101 1 011 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=1 +STP_v 01 101 1 011 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1 +LDP_v 01 101 1 011 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1 +STP_v 10 101 1 011 0 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=1 +LDP_v 10 101 1 011 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=1 + +### Load/store pair — STGP (store allocation tag + pair) + +STGP 01 101 0 001 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1 +STGP 01 101 0 010 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0 +STGP 01 101 0 011 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1 + ### Load/store register — register offset # GPR diff --git a/target/arm/emulate/arm_emulate.c b/target/arm/emulate/arm_emulate.c index bf09e2a67b..6c63a0d0d1 100644 --- a/target/arm/emulate/arm_emulate.c +++ b/target/arm/emulate/arm_emulate.c @@ -122,6 +122,117 @@ static uint64_t load_extend(uint64_t val, int sz, int sign, int ext) return val; } +/* + * Load/store pair: STP, LDP, STNP, LDNP, STGP, LDPSW + * (DDI 0487 C3.3.14 -- C3.3.16) + */ + +static bool trans_STP(DisasContext *ctx, arg_ldstpair *a) +{ + int esize = 1 << a->sz; /* 4 or 8 bytes */ + int64_t offset = (int64_t)a->imm << a->sz; + uint64_t base = base_read(ctx, a->rn); + uint64_t va = a->p ? base : base + offset; /* post-index: unmodified base */ + uint8_t buf[16]; /* max 2 x 8 bytes */ + + uint64_t v1 = gpr_read(ctx, a->rt); + uint64_t v2 = gpr_read(ctx, a->rt2); + memcpy(buf, &v1, esize); + memcpy(buf + esize, &v2, esize); + + if (mem_write(ctx, va, buf, 2 * esize) != 0) { + return true; + } + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +static bool trans_LDP(DisasContext *ctx, arg_ldstpair *a) +{ + int esize = 1 << a->sz; + int64_t offset = (int64_t)a->imm << a->sz; + uint64_t base = base_read(ctx, a->rn); + uint64_t va = a->p ? base : base + offset; + uint8_t buf[16]; + uint64_t v1 = 0, v2 = 0; + + if (mem_read(ctx, va, buf, 2 * esize) != 0) { + return true; + } + memcpy(&v1, buf, esize); + memcpy(&v2, buf + esize, esize); + + /* LDPSW: sign-extend 32-bit values to 64-bit (sign=1, sz=2) */ + if (a->sign) { + v1 = sign_extend(v1, 8 * esize); + v2 = sign_extend(v2, 8 * esize); + } + + gpr_write(ctx, a->rt, v1); + gpr_write(ctx, a->rt2, v2); + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +/* STGP: tag operation is a NOP for emulation; data stored via STP */ +static bool trans_STGP(DisasContext *ctx, arg_ldstpair *a) +{ + return trans_STP(ctx, a); +} + +/* + * SIMD/FP load/store pair: STP_v, LDP_v + * (DDI 0487 C3.3.14 -- C3.3.16) + */ + +static bool trans_STP_v(DisasContext *ctx, arg_ldstpair *a) +{ + int esize = 1 << a->sz; /* 4, 8, or 16 bytes */ + int64_t offset = (int64_t)a->imm << a->sz; + uint64_t base = base_read(ctx, a->rn); + uint64_t va = a->p ? base : base + offset; + uint8_t buf[32]; /* max 2 x 16 bytes */ + + fpreg_read(ctx, a->rt, buf, esize); + fpreg_read(ctx, a->rt2, buf + esize, esize); + + if (mem_write(ctx, va, buf, 2 * esize) != 0) { + return true; + } + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +static bool trans_LDP_v(DisasContext *ctx, arg_ldstpair *a) +{ + int esize = 1 << a->sz; + int64_t offset = (int64_t)a->imm << a->sz; + uint64_t base = base_read(ctx, a->rn); + uint64_t va = a->p ? base : base + offset; + uint8_t buf[32]; + + if (mem_read(ctx, va, buf, 2 * esize) != 0) { + return true; + } + + fpreg_write(ctx, a->rt, buf, esize); + fpreg_write(ctx, a->rt2, buf + esize, esize); + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + /* Load/store single -- immediate (GPR) (DDI 0487 C3.3.8 -- C3.3.13) */ static bool trans_STR_i(DisasContext *ctx, arg_ldst_imm *a) -- 2.54.0 (Apple Git-157)