/* * RISC-V translation routines for the RV64 Zacas Standard Extension. * * Copyright (c) 2020-2023 PLCT Lab * * 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 . */ #define REQUIRE_ZACAS(ctx) do { \ if (!ctx->cfg_ptr->ext_zacas) { \ return false; \ } \ } while (0) static bool trans_amocas_w(DisasContext *ctx, arg_amocas_w *a) { REQUIRE_ZACAS(ctx); return gen_cmpxchg(ctx, a, MO_ALIGN | MO_TESL); } static TCGv_i64 get_gpr_pair(DisasContext *ctx, int reg_num) { TCGv_i64 t; assert(get_ol(ctx) == MXL_RV32); if (reg_num == 0) { return tcg_constant_i64(0); } t = tcg_temp_new_i64(); tcg_gen_concat_tl_i64(t, cpu_gpr[reg_num], cpu_gpr[reg_num + 1]); return t; } static void gen_set_gpr_pair(DisasContext *ctx, int reg_num, TCGv_i64 t) { assert(get_ol(ctx) == MXL_RV32); if (reg_num != 0) { #ifdef TARGET_RISCV32 tcg_gen_extr_i64_i32(cpu_gpr[reg_num], cpu_gpr[reg_num + 1], t); #else tcg_gen_ext32s_i64(cpu_gpr[reg_num], t); tcg_gen_sari_i64(cpu_gpr[reg_num + 1], t, 32); #endif if (get_xl_max(ctx) == MXL_RV128) { tcg_gen_sari_tl(cpu_gprh[reg_num], cpu_gpr[reg_num], 63); tcg_gen_sari_tl(cpu_gprh[reg_num + 1], cpu_gpr[reg_num + 1], 63); } } } static bool gen_cmpxchg64(DisasContext *ctx, arg_atomic *a, MemOp mop) { /* * Encodings with odd numbered registers specified in rs2 and rd are * reserved. */ if ((a->rs2 | a->rd) & 1) { return false; } TCGv_i64 dest = get_gpr_pair(ctx, a->rd); TCGv src1 = get_address(ctx, a->rs1, 0); TCGv_i64 src2 = get_gpr_pair(ctx, a->rs2); decode_save_opc(ctx); tcg_gen_atomic_cmpxchg_i64(dest, src1, dest, src2, ctx->mem_idx, mop); gen_set_gpr_pair(ctx, a->rd, dest); return true; } static bool trans_amocas_d(DisasContext *ctx, arg_amocas_d *a) { REQUIRE_ZACAS(ctx); switch (get_ol(ctx)) { case MXL_RV32: return gen_cmpxchg64(ctx, a, MO_ALIGN | MO_TEUQ); case MXL_RV64: case MXL_RV128: return gen_cmpxchg(ctx, a, MO_ALIGN | MO_TEUQ); default: g_assert_not_reached(); } } static bool trans_amocas_q(DisasContext *ctx, arg_amocas_q *a) { REQUIRE_ZACAS(ctx); REQUIRE_64BIT(ctx); /* * Encodings with odd numbered registers specified in rs2 and rd are * reserved. */ if ((a->rs2 | a->rd) & 1) { return false; } #ifdef TARGET_RISCV64 TCGv_i128 dest = tcg_temp_new_i128(); TCGv src1 = get_address(ctx, a->rs1, 0); TCGv_i128 src2 = tcg_temp_new_i128(); TCGv_i64 src2l = get_gpr(ctx, a->rs2, EXT_NONE); TCGv_i64 src2h = get_gpr(ctx, a->rs2 == 0 ? 0 : a->rs2 + 1, EXT_NONE); TCGv_i64 destl = get_gpr(ctx, a->rd, EXT_NONE); TCGv_i64 desth = get_gpr(ctx, a->rd == 0 ? 0 : a->rd + 1, EXT_NONE); tcg_gen_concat_i64_i128(src2, src2l, src2h); tcg_gen_concat_i64_i128(dest, destl, desth); decode_save_opc(ctx); tcg_gen_atomic_cmpxchg_i128(dest, src1, dest, src2, ctx->mem_idx, (MO_ALIGN | MO_TEUO)); tcg_gen_extr_i128_i64(destl, desth, dest); if (a->rd != 0) { gen_set_gpr(ctx, a->rd, destl); gen_set_gpr(ctx, a->rd + 1, desth); } #endif return true; }