diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ac4a6c7eec..a0414bd956 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -85,6 +85,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zihintpause, PRIV_VERSION_1_10_0, ext_zihintpause),
ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul),
ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs),
+ ISA_EXT_DATA_ENTRY(zalasr, PRIV_VERSION_1_12_0, ext_zalasr),
ISA_EXT_DATA_ENTRY(zfa, PRIV_VERSION_1_12_0, ext_zfa),
ISA_EXT_DATA_ENTRY(zfbfmin, PRIV_VERSION_1_12_0, ext_zfbfmin),
ISA_EXT_DATA_ENTRY(zfh, PRIV_VERSION_1_11_0, ext_zfh),
@@ -1248,6 +1249,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] =
{
MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true),
MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true),
MULTI_EXT_CFG_BOOL("zfa", ext_zfa, true),
+ MULTI_EXT_CFG_BOOL("zalasr", ext_zalasr, true),
MULTI_EXT_CFG_BOOL("zfh", ext_zfh, false),
MULTI_EXT_CFG_BOOL("zfhmin", ext_zfhmin, false),
MULTI_EXT_CFG_BOOL("zve32f", ext_zve32f, false),
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index 0e6a0f245c..8e4f9282fd 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -76,6 +76,7 @@ struct RISCVCPUConfig {
bool ext_svpbmt;
bool ext_zdinx;
bool ext_zawrs;
+ bool ext_zalasr;
bool ext_zfa;
bool ext_zfbfmin;
bool ext_zfh;
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 33597fe2bb..ba95cdf964 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -70,6 +70,9 @@
@atom_ld ..... aq:1 rl:1 ..... ........ ..... ....... &atomic rs2=0 %rs1 %rd
@atom_st ..... aq:1 rl:1 ..... ........ ..... ....... &atomic %rs2 %rs1 %rd
+@l_aq ..... . rl:1 ..... ........ ..... ....... &atomic rs2=0 %rs1 %rd aq=1
+@s_rl ..... aq:1 . ..... ........ ..... ....... &atomic %rs2 %rs1 rd=0 rl=1
+
@r4_rm ..... .. ..... ..... ... ..... ....... %rs3 %rs2 %rs1 %rm %rd
@r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd
@@ -739,6 +742,18 @@ vsetvl 1000000 ..... ..... 111 ..... 1010111 @r
wrs_nto 000000001101 00000 000 00000 1110011
wrs_sto 000000011101 00000 000 00000 1110011
+# *** RV32 Zalasr Standard Extension ***
+lb_aq 00110 1 . 00000 ..... 000 ..... 0101111 @l_aq
+lh_aq 00110 1 . 00000 ..... 001 ..... 0101111 @l_aq
+lw_aq 00110 1 . 00000 ..... 010 ..... 0101111 @l_aq
+sb_rl 00111 . 1 ..... ..... 000 00000 0101111 @s_rl
+sh_rl 00111 . 1 ..... ..... 001 00000 0101111 @s_rl
+sw_rl 00111 . 1 ..... ..... 010 00000 0101111 @s_rl
+
+# *** RV64 Zalasr Standard Extension (in addition to RV32 Zalasr) ***
+ld_aq 00110 1 . 00000 ..... 011 ..... 0101111 @l_aq
+sd_rl 00111 . 1 ..... ..... 011 00000 0101111 @s_rl
+
# *** RV32 Zba Standard Extension ***
sh1add 0010000 .......... 010 ..... 0110011 @r
sh2add 0010000 .......... 100 ..... 0110011 @r
diff --git a/target/riscv/insn_trans/trans_rvzalasr.c.inc
b/target/riscv/insn_trans/trans_rvzalasr.c.inc
new file mode 100644
index 0000000000..cee81ce8b8
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvzalasr.c.inc
@@ -0,0 +1,112 @@
+/*
+ * RISC-V translation routines for the Zzlasr Standard Extension.
+ *
+ * Copyright (c) 2023 Brendan Sweeney, brs@berkeley.edu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define REQUIRE_ZALASR(ctx) do { \
+ if (!ctx->cfg_ptr->ext_zalasr) { \
+ return false; \
+ } \
+} while (0)
+
+static bool gen_l_aq(DisasContext *ctx, arg_atomic *a, MemOp mop)
+{
+ TCGv src1;
+
+ decode_save_opc(ctx);
+ src1 = get_address(ctx, a->rs1, 0);
+ if (a->rl) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ }
+ tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop);
+ if (a->aq) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
+ /* Put data in load_val. */
+ gen_set_gpr(ctx, a->rd, load_val);
+
+ return true;
+}
+
+static bool trans_lb_aq(DisasContext *ctx, arg_lb_aq *a)
+{
+ REQUIRE_ZALASR(ctx);
+ return gen_l_aq(ctx, a, (MO_ALIGN | MO_SB));
+}
+
+static bool trans_lh_aq(DisasContext *ctx, arg_lh_aq *a)
+{
+ REQUIRE_ZALASR(ctx);
+ return gen_l_aq(ctx, a, (MO_ALIGN | MO_TESW));
+}
+
+static bool trans_lw_aq(DisasContext *ctx, arg_lw_aq *a)
+{
+ REQUIRE_ZALASR(ctx);
+ return gen_l_aq(ctx, a, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_ld_aq(DisasContext *ctx, arg_lw_aq *a)
+{
+ REQUIRE_ZALASR(ctx);
+ REQUIRE_64_OR_128BIT(ctx);
+ return gen_l_aq(ctx, a, (MO_ALIGN | MO_TESQ));
+}
+
+static bool gen_s_rl(DisasContext *ctx, arg_atomic *a, MemOp mop)
+{
+ TCGv src1, src2;
+
+ decode_save_opc(ctx);
+ src1 = get_address(ctx, a->rs1, 0);
+
+ src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+
+ if (a->rl) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ }
+ tcg_gen_qemu_st_i64(src2, src1, ctx->mem_idx, mop);
+ if (a->aq) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
+
+ return true;
+}
+
+static bool trans_sb_rl(DisasContext *ctx, arg_sb_rl *a)
+{
+ REQUIRE_ZALASR(ctx);
+ return gen_s_rl(ctx, a, (MO_ALIGN | MO_SB));
+}
+
+static bool trans_sh_rl(DisasContext *ctx, arg_sh_rl *a)
+{
+ REQUIRE_ZALASR(ctx);
+ return gen_s_rl(ctx, a, (MO_ALIGN | MO_TESW));
+}
+
+static bool trans_sw_rl(DisasContext *ctx, arg_sw_rl *a)
+{
+ REQUIRE_ZALASR(ctx);
+ return gen_s_rl(ctx, a, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_sd_rl(DisasContext *ctx, arg_sd_rl *a)
+{
+ REQUIRE_ZALASR(ctx);
+ REQUIRE_64_OR_128BIT(ctx);
+ return gen_s_rl(ctx, a, (MO_ALIGN | MO_TEUQ));
+}
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index f0be79bb16..bfcf1ff1d8 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1091,6 +1091,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase,
target_ulong pc)
#include "insn_trans/trans_rvzicond.c.inc"
#include "insn_trans/trans_rvzawrs.c.inc"
#include "insn_trans/trans_rvzicbo.c.inc"
+#include "insn_trans/trans_rvzalasr.c.inc"
#include "insn_trans/trans_rvzfa.c.inc"
#include "insn_trans/trans_rvzfh.c.inc"
