Commit d4a80ddb3c for qemu.org
commit d4a80ddb3c37d1c0a2f18db4298e7b7e9c7fc07b
Author: Brian Cain <brian.cain@oss.qualcomm.com>
Date: Tue Sep 8 21:01:31 2026 -0700
target/hexagon: add the v79 instructions
v79 adds a ":nt" non-temporal cache-locality hint to the
post-increment store family and to dcfetch/dczeroa.
None of the ":nt" mnemonics are accepted by the assembler yet, so the new
test embeds them via .word.
Reviewed-by: Marco Liebel <marco.liebel@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc
index d12f6ac4b1..8b4eb27d68 100644
--- a/target/hexagon/attribs_def.h.inc
+++ b/target/hexagon/attribs_def.h.inc
@@ -21,6 +21,8 @@ DEF_ATTRIB(AA_DUMMY, "Dummy Zeroth Attribute", "", "")
/* Misc */
DEF_ATTRIB(EXTENSION, "Extension instruction", "", "")
+DEF_ATTRIB(NA_NT, "Non-Allocating Non-Temporal instruction", "", "")
+
DEF_ATTRIB(PRIV, "Not available in user or guest mode", "", "")
DEF_ATTRIB(GUEST, "Not available in user mode", "", "")
diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def
index 1fce318b2b..fca8f8aeb1 100644
--- a/target/hexagon/imported/encode_pp.def
+++ b/target/hexagon/imported/encode_pp.def
@@ -407,6 +407,7 @@ DEF_ENC32(R6_release_st_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --1011dd")
DEF_EXT_SPACE(EXTRACTW, ICLASS_LD" 001 0 000 iiiii PP0iiiii 001iiiii")
DEF_ENC32(Y2_dcfetchbo, ICLASS_LD" 010 0 000 sssss PP0--iii iiiiiiii")
+DEF_ENC32(Y2_dcfetchbo_nt,"10010100000sssssPP10-iiiiiiiiiii")
@@ -473,6 +474,13 @@ STD_ST_ENC(rbnew, "1 101","00ttt")
STD_ST_ENC(rhnew, "1 101","01ttt")
STD_ST_ENC(rinew, "1 101","10ttt")
+/* Non-temporal post-increment stores: the OPC nibble's high bit, always
+ * 1 above, is repurposed as the "nt" hint for this addressing mode only. */
+DEF_ENC32(S2_storerb_pi_nt,"10101010000xxxxxPP0ttttt0iiii-0-")
+DEF_ENC32(S2_storerh_pi_nt,"10101010010xxxxxPP0ttttt0iiii-0-")
+DEF_ENC32(S2_storeri_pi_nt,"10101010100xxxxxPP0ttttt0iiii-0-")
+DEF_ENC32(S2_storerd_pi_nt,"10101010110xxxxxPP0ttttt0iiii-00")
+
STD_PST_ENC(rb, "1 000","ttttt")
STD_PST_ENC(rh, "1 010","ttttt")
STD_PST_ENC(rf, "1 011","ttttt")
@@ -482,6 +490,16 @@ STD_PST_ENC(rbnew, "1 101","00ttt")
STD_PST_ENC(rhnew, "1 101","01ttt")
STD_PST_ENC(rinew, "1 101","10ttt")
+/* Predicated forms of the non-temporal post-increment stores above. */
+DEF_ENC32(S2_pstorerbt_pi_nt,"10101010000xxxxxPP1ttttt0iiii0vv")
+DEF_ENC32(S2_pstorerbf_pi_nt,"10101010000xxxxxPP1ttttt0iiii1vv")
+DEF_ENC32(S2_pstorerht_pi_nt,"10101010010xxxxxPP1ttttt0iiii0vv")
+DEF_ENC32(S2_pstorerhf_pi_nt,"10101010010xxxxxPP1ttttt0iiii1vv")
+DEF_ENC32(S2_pstorerit_pi_nt,"10101010100xxxxxPP1ttttt0iiii0vv")
+DEF_ENC32(S2_pstorerif_pi_nt,"10101010100xxxxxPP1ttttt0iiii1vv")
+DEF_ENC32(S2_pstorerdt_pi_nt,"10101010110xxxxxPP1ttttt0iiii0vv")
+DEF_ENC32(S2_pstorerdf_pi_nt,"10101010110xxxxxPP1ttttt0iiii1vv")
+
/* User */
@@ -492,6 +510,7 @@ STD_PST_ENC(rinew, "1 101","10ttt")
DEF_ENC32(S2_allocframe, ICLASS_ST" 000 01 00xxxxx PP000iii iiiiiiii")
DEF_ENC32(Y5_l2locka, ICLASS_ST" 000 01 11sssss PP1----- ------dd")
DEF_ENC32(Y2_dczeroa, ICLASS_ST" 000 01 10sssss PP0----- --------")
+DEF_ENC32(Y2_dczeroa_nt,"10100000110sssssPP1-------------")
DEF_ENC32(Y2_barrier, ICLASS_ST" 100 00 00----- PP------ 000-----")
diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef
index 4e1e5d5326..7106a0c572 100644
--- a/target/hexagon/imported/ldst.idef
+++ b/target/hexagon/imported/ldst.idef
@@ -118,6 +118,16 @@ STD_ST_AMODES(storerh, "Rt32", "memh","Store Half integer",ATTRIBS(A_REGWRSIZE_2
STD_ST_AMODES(storerf, "Rt.H32", "memh","Store Upper Half integer",ATTRIBS(A_REGWRSIZE_2B,A_MEMSIZE_2B,A_STORE),"1",fSTORE(1,2,EA,fGETHALF(1,RtV)),1)
STD_ST_AMODES(storeri, "Rt32", "memw","Store Word",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_STORE),"2",fSTORE(1,4,EA,RtV),2)
STD_ST_AMODES(storerd, "Rtt32","memd","Store Double integer",ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_STORE),"3",fSTORE(1,8,EA,RttV),3)
+
+/*
+ * Non-temporal post-increment stores: same store, with a cache-locality
+ * hint that a normal-priority cache line is unlikely to be reused soon.
+ */
+Q6INSN(S2_storerb_pi_nt,"memb(Rx32++#s4:0):nt=Rt32",ATTRIBS(A_ARCHV2,A_MEMSIZE_1B,A_STORE,A_NA_NT),"Store Byte",{fEA_REG(RxV); fPM_I(RxV,siV); fSTORE(1,1,EA,fGETBYTE(0,RtV)); })
+Q6INSN(S2_storerh_pi_nt,"memh(Rx32++#s4:1):nt=Rt32",ATTRIBS(A_REGWRSIZE_2B,A_ARCHV2,A_MEMSIZE_2B,A_STORE,A_NA_NT),"Store Half integer",{fEA_REG(RxV); fPM_I(RxV,siV); fSTORE(1,2,EA,fGETHALF(0,RtV)); })
+Q6INSN(S2_storeri_pi_nt,"memw(Rx32++#s4:2):nt=Rt32",ATTRIBS(A_REGWRSIZE_4B,A_ARCHV2,A_MEMSIZE_4B,A_STORE,A_NA_NT),"Store Word",{fEA_REG(RxV); fPM_I(RxV,siV); fSTORE(1,4,EA,RtV); })
+Q6INSN(S2_storerd_pi_nt,"memd(Rx32++#s4:3):nt=Rtt32",ATTRIBS(A_REGWRSIZE_8B,A_ARCHV2,A_MEMSIZE_8B,A_STORE,A_NA_NT),"Store Double integer",{fEA_REG(RxV); fPM_I(RxV,siV); fSTORE(1,8,EA,RttV); })
+
STD_ST_AMODES(storerinew, "Nt8.new", "memw","Store Word",ATTRIBS(A_REGWRSIZE_4B,A_NOTE_NEWVAL_SLOT0,A_NVSTORE,A_NOTE_NVSLOT0,A_MEMSIZE_4B,A_STORE,A_RESTRICT_NOSLOT1_STORE),"2",fSTORE(1,4,EA,fNEWREG_ST(NtN)),2)
STD_ST_AMODES(storerbnew, "Nt8.new", "memb","Store Byte",ATTRIBS(A_NOTE_NEWVAL_SLOT0,A_NVSTORE,A_NOTE_NVSLOT0,A_MEMSIZE_1B,A_STORE,A_RESTRICT_NOSLOT1_STORE),"0",fSTORE(1,1,EA,fGETBYTE(0,fNEWREG_ST(NtN))),0)
STD_ST_AMODES(storerhnew, "Nt8.new", "memh","Store Half integer",ATTRIBS(A_REGWRSIZE_2B,A_NOTE_NEWVAL_SLOT0,A_NVSTORE,A_NOTE_NVSLOT0,A_MEMSIZE_2B,A_STORE,A_RESTRICT_NOSLOT1_STORE),"1",fSTORE(1,2,EA,fGETHALF(0,fNEWREG_ST(NtN))),1)
@@ -277,6 +287,17 @@ STD_PST_AMODES(storerh,"Rt32","memh","Store Half integer",ATTRIBS(A_REGWRSIZE_2B
STD_PST_AMODES(storerf,"Rt.H32","memh","Store Upper Half integer",ATTRIBS(A_REGWRSIZE_2B,A_ARCHV2,A_MEMSIZE_2B,A_STORE),"1",1,fSTORE(1,2,EA,fGETHALF(1,RtV)))
STD_PST_AMODES(storeri,"Rt32","memw","Store Word",ATTRIBS(A_REGWRSIZE_4B,A_ARCHV2,A_MEMSIZE_4B,A_STORE),"2",2,fSTORE(1,4,EA,RtV))
STD_PST_AMODES(storerd,"Rtt32","memd","Store Double integer",ATTRIBS(A_REGWRSIZE_8B,A_ARCHV2,A_MEMSIZE_8B,A_STORE),"3",3,fSTORE(1,8,EA,RttV))
+
+/* Predicated forms of the non-temporal post-increment stores above. */
+Q6INSN(S2_pstorerbt_pi_nt,"if (Pv4) memb(Rx32++#s4:0):nt=Rt32",ATTRIBS(A_ARCHV2,A_MEMSIZE_1B,A_STORE,A_NA_NT),"Store Byte",{fEA_REG(RxV); if (fLSBOLD(PvV)){ fPM_I(RxV,siV); fSTORE(1,1,EA,fGETBYTE(0,RtV));} else {STORE_CANCEL(EA);}})
+Q6INSN(S2_pstorerbf_pi_nt,"if (!Pv4) memb(Rx32++#s4:0):nt=Rt32",ATTRIBS(A_ARCHV2,A_MEMSIZE_1B,A_STORE,A_NA_NT),"Store Byte",{fEA_REG(RxV); if (fLSBOLDNOT(PvV)){ fPM_I(RxV,siV); fSTORE(1,1,EA,fGETBYTE(0,RtV));} else {STORE_CANCEL(EA);}})
+Q6INSN(S2_pstorerht_pi_nt,"if (Pv4) memh(Rx32++#s4:1):nt=Rt32",ATTRIBS(A_REGWRSIZE_2B,A_ARCHV2,A_MEMSIZE_2B,A_STORE,A_NA_NT),"Store Half integer",{fEA_REG(RxV); if (fLSBOLD(PvV)){ fPM_I(RxV,siV); fSTORE(1,2,EA,fGETHALF(0,RtV));} else {STORE_CANCEL(EA);}})
+Q6INSN(S2_pstorerhf_pi_nt,"if (!Pv4) memh(Rx32++#s4:1):nt=Rt32",ATTRIBS(A_REGWRSIZE_2B,A_ARCHV2,A_MEMSIZE_2B,A_STORE,A_NA_NT),"Store Half integer",{fEA_REG(RxV); if (fLSBOLDNOT(PvV)){ fPM_I(RxV,siV); fSTORE(1,2,EA,fGETHALF(0,RtV));} else {STORE_CANCEL(EA);}})
+Q6INSN(S2_pstorerit_pi_nt,"if (Pv4) memw(Rx32++#s4:2):nt=Rt32",ATTRIBS(A_REGWRSIZE_4B,A_ARCHV2,A_MEMSIZE_4B,A_STORE,A_NA_NT),"Store Word",{fEA_REG(RxV); if (fLSBOLD(PvV)){ fPM_I(RxV,siV); fSTORE(1,4,EA,RtV);} else {STORE_CANCEL(EA);}})
+Q6INSN(S2_pstorerif_pi_nt,"if (!Pv4) memw(Rx32++#s4:2):nt=Rt32",ATTRIBS(A_REGWRSIZE_4B,A_ARCHV2,A_MEMSIZE_4B,A_STORE,A_NA_NT),"Store Word",{fEA_REG(RxV); if (fLSBOLDNOT(PvV)){ fPM_I(RxV,siV); fSTORE(1,4,EA,RtV);} else {STORE_CANCEL(EA);}})
+Q6INSN(S2_pstorerdt_pi_nt,"if (Pv4) memd(Rx32++#s4:3):nt=Rtt32",ATTRIBS(A_REGWRSIZE_8B,A_ARCHV2,A_MEMSIZE_8B,A_STORE,A_NA_NT),"Store Double integer",{fEA_REG(RxV); if (fLSBOLD(PvV)){ fPM_I(RxV,siV); fSTORE(1,8,EA,RttV);} else {STORE_CANCEL(EA);}})
+Q6INSN(S2_pstorerdf_pi_nt,"if (!Pv4) memd(Rx32++#s4:3):nt=Rtt32",ATTRIBS(A_REGWRSIZE_8B,A_ARCHV2,A_MEMSIZE_8B,A_STORE,A_NA_NT),"Store Double integer",{fEA_REG(RxV); if (fLSBOLDNOT(PvV)){ fPM_I(RxV,siV); fSTORE(1,8,EA,RttV);} else {STORE_CANCEL(EA);}})
+
STD_PST_AMODES(storerinew,"Nt8.new","memw","Store Word",ATTRIBS(A_REGWRSIZE_4B,A_ARCHV2,A_NOTE_NEWVAL_SLOT0,A_NVSTORE,A_NOTE_NVSLOT0,A_MEMSIZE_4B,A_STORE,A_RESTRICT_NOSLOT1_STORE),"2",2,fSTORE(1,4,EA,fNEWREG_ST(NtN)))
STD_PST_AMODES(storerbnew,"Nt8.new","memb","Store Byte",ATTRIBS(A_ARCHV2,A_NOTE_NEWVAL_SLOT0,A_NVSTORE,A_NOTE_NVSLOT0,A_MEMSIZE_1B,A_STORE,A_RESTRICT_NOSLOT1_STORE),"0",0,fSTORE(1,1,EA,fGETBYTE(0,fNEWREG_ST(NtN))))
STD_PST_AMODES(storerhnew,"Nt8.new","memh","Store Half integer",ATTRIBS(A_REGWRSIZE_2B,A_ARCHV2,A_NOTE_NEWVAL_SLOT0,A_NVSTORE,A_NOTE_NVSLOT0,A_MEMSIZE_2B,A_STORE,A_RESTRICT_NOSLOT1_STORE),"1",1,fSTORE(1,2,EA,fGETHALF(0,fNEWREG_ST(NtN))))
diff --git a/target/hexagon/imported/system.idef b/target/hexagon/imported/system.idef
index b44e87565c..6187ada5ab 100644
--- a/target/hexagon/imported/system.idef
+++ b/target/hexagon/imported/system.idef
@@ -238,10 +238,12 @@ Q6INSN(Y6_dmresume,"dmresume(Rs32)",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,
Q6INSN(Y2_dcfetchbo,"dcfetch(Rs32+#u11:3)",ATTRIBS(A_RESTRICT_PREFERSLOT0,A_DCFETCH,A_RESTRICT_NOSLOT1_STORE),"Data Cache Prefetch",{fEA_RI(RsV,uiV); fDCFETCH(EA);})
+Q6INSN(Y2_dcfetchbo_nt,"dcfetch(Rs32+#u11:3):nt",ATTRIBS(A_NA_NT,A_RESTRICT_PREFERSLOT0,A_DCFETCH,A_RESTRICT_NOSLOT1_STORE),"Data Cache Prefetch",{fEA_RI(RsV,uiV); fDCFETCH(EA);})
Q6INSN(Y2_dckill,"dckill",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_DCFLUSHOP),"Data Cache Invalidate",{fDCKILL();})
Q6INSN(Y2_dczeroa,"dczeroa(Rs32)",ATTRIBS(A_STORE,A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCZEROA),"Zero an aligned 32-byte cacheline",{fEA_REG(RsV); fDCZEROA(EA);})
+Q6INSN(Y2_dczeroa_nt,"dczeroa(Rs32):nt",ATTRIBS(A_STORE,A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCZEROA,A_NA_NT),"Zero an aligned 32-byte cacheline",{fEA_REG(RsV); fDCZEROA(EA);})
Q6INSN(Y2_dccleana,"dccleana(Rs32)",ATTRIBS(A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCFLUSHOP),"Data Cache Clean Address",{fEA_REG(RsV); fDCCLEANA(EA);})
Q6INSN(Y2_dccleanidx,"dccleanidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCFLUSHOP),"Data Cache Clean Index",{fDCCLEANIDX(RsV);})
Q6INSN(Y2_dccleaninva,"dccleaninva(Rs32)",ATTRIBS(A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCFLUSHOP),"Data Cache Clean and Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);})
diff --git a/target/hexagon/tag_rev_info.c.inc b/target/hexagon/tag_rev_info.c.inc
index 44513f4680..48bdc52bfd 100644
--- a/target/hexagon/tag_rev_info.c.inc
+++ b/target/hexagon/tag_rev_info.c.inc
@@ -619,6 +619,29 @@ static const struct tag_rev_info tag_rev_info[XX_LAST_OPCODE] = {
[V6_vassign_tmp] = { .introduced = HEX_VER_V69, .removed = HEX_VER_NONE },
[V6_vcombine_tmp] = { .introduced = HEX_VER_V69, .removed = HEX_VER_NONE },
[V6_vmpyuhvs] = { .introduced = HEX_VER_V69, .removed = HEX_VER_NONE },
+
+ [S2_pstorerbf_pi_nt] = { .introduced = HEX_VER_V79,
+ .removed = HEX_VER_NONE },
+ [S2_pstorerbt_pi_nt] = { .introduced = HEX_VER_V79,
+ .removed = HEX_VER_NONE },
+ [S2_pstorerdf_pi_nt] = { .introduced = HEX_VER_V79,
+ .removed = HEX_VER_NONE },
+ [S2_pstorerdt_pi_nt] = { .introduced = HEX_VER_V79,
+ .removed = HEX_VER_NONE },
+ [S2_pstorerhf_pi_nt] = { .introduced = HEX_VER_V79,
+ .removed = HEX_VER_NONE },
+ [S2_pstorerht_pi_nt] = { .introduced = HEX_VER_V79,
+ .removed = HEX_VER_NONE },
+ [S2_pstorerif_pi_nt] = { .introduced = HEX_VER_V79,
+ .removed = HEX_VER_NONE },
+ [S2_pstorerit_pi_nt] = { .introduced = HEX_VER_V79,
+ .removed = HEX_VER_NONE },
+ [S2_storerb_pi_nt] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
+ [S2_storerd_pi_nt] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
+ [S2_storerh_pi_nt] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
+ [S2_storeri_pi_nt] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
+ [Y2_dcfetchbo_nt] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
+ [Y2_dczeroa_nt] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
};
#endif /* HEXAGON_TAG_ARCH_TABLE_H */
diff --git a/tests/tcg/hexagon/check_rev_gating.c b/tests/tcg/hexagon/check_rev_gating.c
index d5295bf24a..3f48ab9cd3 100644
--- a/tests/tcg/hexagon/check_rev_gating.c
+++ b/tests/tcg/hexagon/check_rev_gating.c
@@ -3,12 +3,15 @@
* are rejected with SIGILL.
*
* Compiled with -mv66 so that e_flags selects CPU v66. The test embeds
- * instructions from v68 through v73 via .word encoding: the assembler
- * enforces the selected CPU's own minimum version, so none of these --
- * including ones it otherwise knows how to assemble at their own
- * target, such as callrh or unpause -- can be written as themselves in
- * a file built for v66. The revision-gated decoder must reject every
- * one of them, and linux-user must deliver SIGILL.
+ * instructions from v68 up through v79 via .word encoding: the
+ * assembler enforces the selected CPU's own minimum version, so none
+ * of these -- including ones it otherwise knows how to assemble at
+ * their own target, such as callrh or unpause -- can be written as
+ * themselves in a file built for v66. The v79 non-temporal hints
+ * (":nt") aren't known to the assembler at any target yet, so those
+ * would need .word regardless. The revision-gated decoder must reject
+ * representative instructions from each family, and linux-user must
+ * deliver SIGILL.
*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -108,6 +111,17 @@ TRY_FUNC(v73_jumprh,
TRY_FUNC(v73_unpause,
".word 0x57e0d000 /* unpause */\n")
+TRY_FUNC(v79_storeri_pi_nt,
+ ".word 0xaa82c308 /* memw(r2++#4):nt = r3 */\n")
+TRY_FUNC(v79_pstorerit_pi_nt,
+ ".word 0xaa82e308 /* if (p0) memw(r2++#4):nt = r3 */\n")
+TRY_FUNC(v79_pstorerif_pi_nt,
+ ".word 0xaa82e30c /* if (!p0) memw(r2++#4):nt = r3 */\n")
+TRY_FUNC(v79_dczeroa_nt,
+ ".word 0xa0c2e000 /* dczeroa(r2):nt */\n")
+TRY_FUNC(v79_dcfetchbo_nt,
+ ".word 0x9402e000 /* dcfetch(r2+#0):nt */\n")
+
int main(void)
{
struct sigaction act;
@@ -140,6 +154,12 @@ int main(void)
assert(try_v73_jumprh() == SIGILL);
assert(try_v73_unpause() == SIGILL);
+ assert(try_v79_storeri_pi_nt() == SIGILL);
+ assert(try_v79_pstorerit_pi_nt() == SIGILL);
+ assert(try_v79_pstorerif_pi_nt() == SIGILL);
+ assert(try_v79_dczeroa_nt() == SIGILL);
+ assert(try_v79_dcfetchbo_nt() == SIGILL);
+
assert(signals_handled == expected_signals);
puts("PASS");
diff --git a/tests/tcg/hexagon/meson.build b/tests/tcg/hexagon/meson.build
index 4a2826c427..6e36a9a122 100644
--- a/tests/tcg/hexagon/meson.build
+++ b/tests/tcg/hexagon/meson.build
@@ -101,6 +101,7 @@ tests += {
'v68_hvx.c': {'cflags': [cflags, '-mhvx', '-Wno-unused-function', '-mv68']},
'v69_hvx.c': {'cflags': [cflags, '-mhvx', '-Wno-unused-function', '-mv69']},
'v73_scalar.c': {'cflags': [cflags, '-Wno-unused-function', '-mv73']},
+ 'v79_scalar.c': {'cflags': [cflags, '-Wno-unused-function', '-mv79']},
'valid-slots.c': {'cflags': cflags},
'vector_add_int.c': {'cflags': [cflags, '-mhvx', '-fvectorize']},
}
diff --git a/tests/tcg/hexagon/v79_scalar.c b/tests/tcg/hexagon/v79_scalar.c
new file mode 100644
index 0000000000..81eb277b73
--- /dev/null
+++ b/tests/tcg/hexagon/v79_scalar.c
@@ -0,0 +1,157 @@
+/*
+ * Test the scalar core instructions that are new in v79.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+int err;
+
+static void __check32(int line, uint32_t result, uint32_t expect)
+{
+ if (result != expect) {
+ printf("ERROR at line %d: 0x%08x != 0x%08x\n", line, result, expect);
+ err++;
+ }
+}
+
+#define check32(RES, EXP) __check32(__LINE__, RES, EXP)
+
+static uint32_t sbuf[4];
+static uint32_t newp;
+
+/* S2_storeri_pi_nt: memw(Rx32++#4):nt = Rt32 */
+static void test_storeri_pi_nt(void)
+{
+ uint32_t *p = sbuf;
+
+ memset(sbuf, 0xff, sizeof(sbuf));
+ asm volatile(
+ "r2 = %1\n\t"
+ "r3 = #0x12345678\n\t"
+ ".word 0xaa82c308\n\t" /* memw(r2++#4):nt = r3 */
+ "r5 = ##newp\n\t"
+ "memw(r5 + #0) = r2\n\t"
+ : "+m"(newp)
+ : "r"(p)
+ : "r2", "r3", "r5", "memory");
+ check32(sbuf[0], 0x12345678);
+ check32(newp, (uint32_t)(uintptr_t)(sbuf + 1));
+}
+
+static uint8_t bbuf[4];
+
+/* S2_storerb_pi_nt: memb(Rx32++#1):nt = Rt32 */
+static void test_storerb_pi_nt(void)
+{
+ uint32_t *p = (uint32_t *)bbuf;
+
+ memset(bbuf, 0xff, sizeof(bbuf));
+ asm volatile(
+ "r2 = %1\n\t"
+ "r3 = #0x42\n\t"
+ ".word 0xaa02c308\n\t" /* memb(r2++#1):nt = r3 */
+ "r5 = ##newp\n\t"
+ "memw(r5 + #0) = r2\n\t"
+ : "+m"(newp)
+ : "r"(p)
+ : "r2", "r3", "r5", "memory");
+ check32(bbuf[0], 0x42);
+ check32(newp, (uint32_t)(uintptr_t)(bbuf + 1));
+}
+
+/* S2_pstorerit_pi_nt: if (Pv4) memw(Rx32++#4):nt = Rt32, predicate true */
+static void test_pstorerit_pi_nt(void)
+{
+ uint32_t *p = sbuf;
+
+ memset(sbuf, 0xff, sizeof(sbuf));
+ asm volatile(
+ "p0 = cmp.eq(r0, r0)\n\t" /* P0 = true */
+ "r2 = %1\n\t"
+ "r3 = #0x11223344\n\t"
+ ".word 0xaa82e308\n\t" /* if (p0) memw(r2++#4):nt = r3 */
+ "r5 = ##newp\n\t"
+ "memw(r5 + #0) = r2\n\t"
+ : "+m"(newp)
+ : "r"(p)
+ : "r0", "r2", "r3", "r5", "p0", "memory");
+ check32(sbuf[0], 0x11223344);
+ check32(newp, (uint32_t)(uintptr_t)(sbuf + 1));
+}
+
+/* S2_pstorerif_pi_nt: if (!Pv4) memw(Rx32++#4):nt = Rt32, predicate false */
+static void test_pstorerif_pi_nt(void)
+{
+ uint32_t *p = sbuf;
+
+ memset(sbuf, 0xff, sizeof(sbuf));
+ asm volatile(
+ "r0 = #1\n\t"
+ "r1 = #2\n\t"
+ "p0 = cmp.eq(r0, r1)\n\t" /* P0 = false */
+ "r2 = %1\n\t"
+ "r3 = #0x99887766\n\t"
+ ".word 0xaa82e30c\n\t" /* if (!p0) memw(r2++#4):nt = r3 */
+ "r5 = ##newp\n\t"
+ "memw(r5 + #0) = r2\n\t"
+ : "+m"(newp)
+ : "r"(p)
+ : "r0", "r1", "r2", "r3", "r5", "p0", "memory");
+ check32(sbuf[0], 0x99887766);
+ check32(newp, (uint32_t)(uintptr_t)(sbuf + 1));
+}
+
+/* Y2_dczeroa_nt: dczeroa(Rs32):nt -- zeroes a 32-byte cacheline */
+static uint8_t cz[64] __attribute__((aligned(32)));
+
+static void test_dczeroa_nt(void)
+{
+ memset(cz, 0xaa, sizeof(cz));
+ asm volatile(
+ "r2 = %1\n\t"
+ ".word 0xa0c2e000\n\t" /* dczeroa(r2):nt */
+ : "+m"(cz)
+ : "r"(cz)
+ : "r2", "memory");
+ for (int i = 0; i < 32; i++) {
+ check32(cz[i], 0);
+ }
+ for (int i = 32; i < 64; i++) {
+ check32(cz[i], 0xaa);
+ }
+}
+
+/* Y2_dcfetchbo_nt: dcfetch(Rs32+#0):nt -- a hint, must not fault or store */
+static uint8_t df[32] __attribute__((aligned(8)));
+
+static void test_dcfetchbo_nt(void)
+{
+ memset(df, 0x55, sizeof(df));
+ asm volatile(
+ "r2 = %1\n\t"
+ ".word 0x9402e000\n\t" /* dcfetch(r2+#0):nt */
+ : "+m"(df)
+ : "r"(df)
+ : "r2", "memory");
+ for (int i = 0; i < 32; i++) {
+ check32(df[i], 0x55);
+ }
+}
+
+int main()
+{
+ test_storeri_pi_nt();
+ test_storerb_pi_nt();
+ test_pstorerit_pi_nt();
+ test_pstorerif_pi_nt();
+ test_dczeroa_nt();
+ test_dcfetchbo_nt();
+
+ puts(err ? "FAIL" : "PASS");
+ return err ? 1 : 0;
+}