| 1 | /* |
| 2 | * RISC-V translation routines for the MIPS extensions (xmips*). |
| 3 | * |
| 4 | * Copyright (c) 2025 MIPS |
| 5 | * |
| 6 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 7 | * |
| 8 | * Reference: MIPS P8700 instructions |
| 9 | * (https://mips.com/products/hardware/p8700/) |
| 10 | */ |
| 11 | |
| 12 | #define REQUIRE_XMIPSCBOP(ctx) do { \ |
| 13 | if (!ctx->cfg_ptr->ext_xmipscbop) { \ |
| 14 | return false; \ |
| 15 | } \ |
| 16 | } while (0) |
| 17 | |
| 18 | #define REQUIRE_XMIPSCMOV(ctx) do { \ |
| 19 | if (!ctx->cfg_ptr->ext_xmipscmov) { \ |
| 20 | return false; \ |
| 21 | } \ |
| 22 | } while (0) |
| 23 | |
| 24 | #define REQUIRE_XMIPSLSP(ctx) do { \ |
| 25 | if (!ctx->cfg_ptr->ext_xmipslsp) { \ |
| 26 | return false; \ |
| 27 | } \ |
| 28 | } while (0) |
| 29 | |
| 30 | /* Conditional move by MIPS. */ |
| 31 | static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) |
| 32 | { |
| 33 | REQUIRE_XMIPSCMOV(ctx); |
| 34 | |
| 35 | TCGv zero, source1, source2, source3; |
| 36 | zero = tcg_constant_tl(0); |
| 37 | source1 = get_gpr(ctx, a->rs1, EXT_NONE); |
| 38 | source2 = get_gpr(ctx, a->rs2, EXT_NONE); |
| 39 | source3 = get_gpr(ctx, a->rs3, EXT_NONE); |
| 40 | |
| 41 | tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[a->rd], |
| 42 | source2, zero, source1, source3); |
| 43 | |
| 44 | return true; |
| 45 | } |
| 46 | |
| 47 | /* Load Doubleword Pair. */ |
| 48 | static bool trans_ldp(DisasContext *ctx, arg_ldp *a) |
| 49 | { |
| 50 | MemOp memop = MO_SQ | ctx->mo_endianness; |
| 51 | |
| 52 | REQUIRE_XMIPSLSP(ctx); |
| 53 | REQUIRE_64_OR_128BIT(ctx); |
| 54 | |
| 55 | TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); |
| 56 | TCGv dest0 = dest_gpr(ctx, a->rd); |
| 57 | TCGv dest1 = dest_gpr(ctx, a->rs3); |
| 58 | TCGv addr = tcg_temp_new(); |
| 59 | |
| 60 | tcg_gen_addi_tl(addr, src, a->imm_y); |
| 61 | tcg_gen_qemu_ld_tl(dest0, addr, ctx->mem_idx, memop); |
| 62 | gen_set_gpr(ctx, a->rd, dest0); |
| 63 | |
| 64 | tcg_gen_addi_tl(addr, addr, 8); |
| 65 | tcg_gen_qemu_ld_tl(dest1, addr, ctx->mem_idx, memop); |
| 66 | gen_set_gpr(ctx, a->rs3, dest1); |
| 67 | |
| 68 | return true; |
| 69 | } |
| 70 | |
| 71 | /* Load Word Pair. */ |
| 72 | static bool trans_lwp(DisasContext *ctx, arg_lwp *a) |
| 73 | { |
| 74 | MemOp memop = MO_SL | ctx->mo_endianness; |
| 75 | |
| 76 | REQUIRE_XMIPSLSP(ctx); |
| 77 | |
| 78 | TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); |
| 79 | TCGv dest0 = dest_gpr(ctx, a->rd); |
| 80 | TCGv dest1 = dest_gpr(ctx, a->rs3); |
| 81 | TCGv addr = tcg_temp_new(); |
| 82 | |
| 83 | tcg_gen_addi_tl(addr, src, a->imm_x); |
| 84 | tcg_gen_qemu_ld_tl(dest0, addr, ctx->mem_idx, memop); |
| 85 | gen_set_gpr(ctx, a->rd, dest0); |
| 86 | |
| 87 | tcg_gen_addi_tl(addr, addr, 4); |
| 88 | tcg_gen_qemu_ld_tl(dest1, addr, ctx->mem_idx, memop); |
| 89 | gen_set_gpr(ctx, a->rs3, dest1); |
| 90 | |
| 91 | return true; |
| 92 | } |
| 93 | |
| 94 | /* Store Doubleword Pair. */ |
| 95 | static bool trans_sdp(DisasContext *ctx, arg_sdp *a) |
| 96 | { |
| 97 | MemOp memop = MO_UQ | ctx->mo_endianness; |
| 98 | |
| 99 | REQUIRE_XMIPSLSP(ctx); |
| 100 | REQUIRE_64_OR_128BIT(ctx); |
| 101 | |
| 102 | TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); |
| 103 | TCGv data0 = get_gpr(ctx, a->rs2, EXT_NONE); |
| 104 | TCGv data1 = get_gpr(ctx, a->rs3, EXT_NONE); |
| 105 | TCGv addr = tcg_temp_new(); |
| 106 | |
| 107 | tcg_gen_addi_tl(addr, src, a->imm_w); |
| 108 | tcg_gen_qemu_st_tl(data0, addr, ctx->mem_idx, memop); |
| 109 | |
| 110 | tcg_gen_addi_tl(addr, addr, 8); |
| 111 | tcg_gen_qemu_st_tl(data1, addr, ctx->mem_idx, memop); |
| 112 | |
| 113 | return true; |
| 114 | } |
| 115 | |
| 116 | /* Store Word Pair. */ |
| 117 | static bool trans_swp(DisasContext *ctx, arg_swp *a) |
| 118 | { |
| 119 | MemOp memop = MO_SL | ctx->mo_endianness; |
| 120 | |
| 121 | REQUIRE_XMIPSLSP(ctx); |
| 122 | |
| 123 | TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); |
| 124 | TCGv data0 = get_gpr(ctx, a->rs2, EXT_NONE); |
| 125 | TCGv data1 = get_gpr(ctx, a->rs3, EXT_NONE); |
| 126 | TCGv addr = tcg_temp_new(); |
| 127 | |
| 128 | tcg_gen_addi_tl(addr, src, a->imm_v); |
| 129 | tcg_gen_qemu_st_tl(data0, addr, ctx->mem_idx, memop); |
| 130 | |
| 131 | tcg_gen_addi_tl(addr, addr, 4); |
| 132 | tcg_gen_qemu_st_tl(data1, addr, ctx->mem_idx, memop); |
| 133 | |
| 134 | return true; |
| 135 | } |
| 136 | |
| 137 | /* Move data from memory into cache. */ |
| 138 | static bool trans_pref(DisasContext *ctx, arg_pref *a) |
| 139 | { |
| 140 | REQUIRE_XMIPSCBOP(ctx); |
| 141 | |
| 142 | /* Nop */ |
| 143 | return true; |
| 144 | } |