Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Altera Nios II emulation for qemu: main translation routines. |
| 3 | * |
| 4 | * Copyright (C) 2016 Marek Vasut <marex@denx.de> |
| 5 | * Copyright (C) 2012 Chris Wulff <crwulff@gmail.com> |
| 6 | * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> |
| 7 | * (Portions of this file that were originally from nios2sim-ng.) |
| 8 | * |
| 9 | * This library is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU Lesser General Public |
| 11 | * License as published by the Free Software Foundation; either |
| 12 | * version 2.1 of the License, or (at your option) any later version. |
| 13 | * |
| 14 | * This library is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 17 | * Lesser General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU Lesser General Public |
| 20 | * License along with this library; if not, see |
| 21 | * <http://www.gnu.org/licenses/lgpl-2.1.html> |
| 22 | */ |
| 23 | |
Philippe Mathieu-Daudé | 9d80865 | 2017-10-17 13:44:01 -0300 | [diff] [blame] | 24 | #include "qemu/osdep.h" |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 25 | #include "cpu.h" |
Philippe Mathieu-Daudé | dcb32f1 | 2020-01-01 12:23:00 +0100 | [diff] [blame] | 26 | #include "tcg/tcg-op.h" |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 27 | #include "exec/exec-all.h" |
| 28 | #include "disas/disas.h" |
| 29 | #include "exec/helper-proto.h" |
| 30 | #include "exec/helper-gen.h" |
| 31 | #include "exec/log.h" |
Lluís Vilanova | 77fc6f5 | 2017-07-14 11:21:37 +0300 | [diff] [blame] | 32 | #include "exec/translator.h" |
Markus Armbruster | 90c84c5 | 2019-04-17 21:18:02 +0200 | [diff] [blame] | 33 | #include "qemu/qemu-print.h" |
Richard Henderson | 24ca313 | 2022-04-21 08:17:02 -0700 | [diff] [blame] | 34 | #include "semihosting/semihost.h" |
Lluís Vilanova | 77fc6f5 | 2017-07-14 11:21:37 +0300 | [diff] [blame] | 35 | |
Richard Henderson | d53106c | 2023-03-31 10:37:04 -0700 | [diff] [blame] | 36 | #define HELPER_H "helper.h" |
| 37 | #include "exec/helper-info.c.inc" |
| 38 | #undef HELPER_H |
| 39 | |
| 40 | |
Lluís Vilanova | 77fc6f5 | 2017-07-14 11:21:37 +0300 | [diff] [blame] | 41 | /* is_jmp field values */ |
Lluís Vilanova | 77fc6f5 | 2017-07-14 11:21:37 +0300 | [diff] [blame] | 42 | #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 43 | |
| 44 | #define INSTRUCTION_FLG(func, flags) { (func), (flags) } |
| 45 | #define INSTRUCTION(func) \ |
| 46 | INSTRUCTION_FLG(func, 0) |
| 47 | #define INSTRUCTION_NOP() \ |
| 48 | INSTRUCTION_FLG(nop, 0) |
| 49 | #define INSTRUCTION_UNIMPLEMENTED() \ |
| 50 | INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL) |
| 51 | #define INSTRUCTION_ILLEGAL() \ |
| 52 | INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL) |
| 53 | |
| 54 | /* Special R-Type instruction opcode */ |
| 55 | #define INSN_R_TYPE 0x3A |
| 56 | |
| 57 | /* I-Type instruction parsing */ |
Richard Henderson | 1746338 | 2022-04-21 08:17:14 -0700 | [diff] [blame] | 58 | typedef struct { |
| 59 | uint8_t op; |
| 60 | union { |
| 61 | uint16_t u; |
| 62 | int16_t s; |
| 63 | } imm16; |
| 64 | uint8_t b; |
| 65 | uint8_t a; |
| 66 | } InstrIType; |
| 67 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 68 | #define I_TYPE(instr, code) \ |
Richard Henderson | 1746338 | 2022-04-21 08:17:14 -0700 | [diff] [blame] | 69 | InstrIType (instr) = { \ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 70 | .op = extract32((code), 0, 6), \ |
Paolo Bonzini | 4ae4b60 | 2017-03-03 17:28:49 +0100 | [diff] [blame] | 71 | .imm16.u = extract32((code), 6, 16), \ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 72 | .b = extract32((code), 22, 5), \ |
| 73 | .a = extract32((code), 27, 5), \ |
| 74 | } |
| 75 | |
Richard Henderson | 3d1f63d | 2022-04-22 09:16:43 -0700 | [diff] [blame] | 76 | typedef target_ulong ImmFromIType(const InstrIType *); |
| 77 | |
| 78 | static target_ulong imm_unsigned(const InstrIType *i) |
| 79 | { |
| 80 | return i->imm16.u; |
| 81 | } |
| 82 | |
| 83 | static target_ulong imm_signed(const InstrIType *i) |
| 84 | { |
| 85 | return i->imm16.s; |
| 86 | } |
| 87 | |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 88 | static target_ulong imm_shifted(const InstrIType *i) |
| 89 | { |
| 90 | return i->imm16.u << 16; |
| 91 | } |
| 92 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 93 | /* R-Type instruction parsing */ |
Richard Henderson | 1746338 | 2022-04-21 08:17:14 -0700 | [diff] [blame] | 94 | typedef struct { |
| 95 | uint8_t op; |
| 96 | uint8_t imm5; |
| 97 | uint8_t opx; |
| 98 | uint8_t c; |
| 99 | uint8_t b; |
| 100 | uint8_t a; |
| 101 | } InstrRType; |
| 102 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 103 | #define R_TYPE(instr, code) \ |
Richard Henderson | 1746338 | 2022-04-21 08:17:14 -0700 | [diff] [blame] | 104 | InstrRType (instr) = { \ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 105 | .op = extract32((code), 0, 6), \ |
| 106 | .imm5 = extract32((code), 6, 5), \ |
| 107 | .opx = extract32((code), 11, 6), \ |
| 108 | .c = extract32((code), 17, 5), \ |
| 109 | .b = extract32((code), 22, 5), \ |
| 110 | .a = extract32((code), 27, 5), \ |
| 111 | } |
| 112 | |
| 113 | /* J-Type instruction parsing */ |
Richard Henderson | 1746338 | 2022-04-21 08:17:14 -0700 | [diff] [blame] | 114 | typedef struct { |
| 115 | uint8_t op; |
| 116 | uint32_t imm26; |
| 117 | } InstrJType; |
| 118 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 119 | #define J_TYPE(instr, code) \ |
Richard Henderson | 1746338 | 2022-04-21 08:17:14 -0700 | [diff] [blame] | 120 | InstrJType (instr) = { \ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 121 | .op = extract32((code), 0, 6), \ |
| 122 | .imm26 = extract32((code), 6, 26), \ |
| 123 | } |
| 124 | |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 125 | typedef void GenFn2i(TCGv, TCGv, target_long); |
Richard Henderson | 7c84904 | 2022-04-22 09:25:30 -0700 | [diff] [blame] | 126 | typedef void GenFn3(TCGv, TCGv, TCGv); |
Richard Henderson | 3099c41 | 2022-04-22 09:28:38 -0700 | [diff] [blame] | 127 | typedef void GenFn4(TCGv, TCGv, TCGv, TCGv); |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 128 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 129 | typedef struct DisasContext { |
Richard Henderson | e9150ea | 2021-06-19 21:44:48 -0700 | [diff] [blame] | 130 | DisasContextBase base; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 131 | target_ulong pc; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 132 | int mem_idx; |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 133 | uint32_t tb_flags; |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 134 | TCGv sink; |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 135 | const ControlRegState *cr_state; |
Richard Henderson | 3a03087 | 2022-04-21 08:17:25 -0700 | [diff] [blame] | 136 | bool eic_present; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 137 | } DisasContext; |
| 138 | |
Richard Henderson | f1ec078 | 2022-04-21 08:16:50 -0700 | [diff] [blame] | 139 | static TCGv cpu_R[NUM_GP_REGS]; |
Richard Henderson | 17a406e | 2022-04-21 08:16:47 -0700 | [diff] [blame] | 140 | static TCGv cpu_pc; |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 141 | #ifndef CONFIG_USER_ONLY |
| 142 | static TCGv cpu_crs_R[NUM_GP_REGS]; |
| 143 | #endif |
Richard Henderson | 438aabe | 2021-06-19 21:38:36 -0700 | [diff] [blame] | 144 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 145 | typedef struct Nios2Instruction { |
| 146 | void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags); |
| 147 | uint32_t flags; |
| 148 | } Nios2Instruction; |
| 149 | |
| 150 | static uint8_t get_opcode(uint32_t code) |
| 151 | { |
| 152 | I_TYPE(instr, code); |
| 153 | return instr.op; |
| 154 | } |
| 155 | |
| 156 | static uint8_t get_opxcode(uint32_t code) |
| 157 | { |
| 158 | R_TYPE(instr, code); |
| 159 | return instr.opx; |
| 160 | } |
| 161 | |
Richard Henderson | 718db07 | 2022-04-21 08:17:13 -0700 | [diff] [blame] | 162 | static TCGv load_gpr(DisasContext *dc, unsigned reg) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 163 | { |
Richard Henderson | 718db07 | 2022-04-21 08:17:13 -0700 | [diff] [blame] | 164 | assert(reg < NUM_GP_REGS); |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 165 | |
| 166 | /* |
| 167 | * With shadow register sets, register r0 does not necessarily contain 0, |
| 168 | * but it is overwhelmingly likely that it does -- software is supposed |
| 169 | * to have set r0 to 0 in every shadow register set before use. |
| 170 | */ |
| 171 | if (unlikely(reg == R_ZERO) && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) { |
Richard Henderson | 718db07 | 2022-04-21 08:17:13 -0700 | [diff] [blame] | 172 | return tcg_constant_tl(0); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 173 | } |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 174 | if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { |
| 175 | return cpu_R[reg]; |
| 176 | } |
| 177 | #ifdef CONFIG_USER_ONLY |
| 178 | g_assert_not_reached(); |
| 179 | #else |
| 180 | return cpu_crs_R[reg]; |
| 181 | #endif |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 182 | } |
| 183 | |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 184 | static TCGv dest_gpr(DisasContext *dc, unsigned reg) |
| 185 | { |
| 186 | assert(reg < NUM_GP_REGS); |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 187 | |
| 188 | /* |
| 189 | * The spec for shadow register sets isn't clear, but we assume that |
| 190 | * writes to r0 are discarded regardless of CRS. |
| 191 | */ |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 192 | if (unlikely(reg == R_ZERO)) { |
| 193 | if (dc->sink == NULL) { |
| 194 | dc->sink = tcg_temp_new(); |
| 195 | } |
| 196 | return dc->sink; |
| 197 | } |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 198 | if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { |
| 199 | return cpu_R[reg]; |
| 200 | } |
| 201 | #ifdef CONFIG_USER_ONLY |
| 202 | g_assert_not_reached(); |
| 203 | #else |
| 204 | return cpu_crs_R[reg]; |
| 205 | #endif |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 206 | } |
| 207 | |
Richard Henderson | e84f176 | 2022-04-21 08:17:28 -0700 | [diff] [blame] | 208 | static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 209 | { |
Richard Henderson | e84f176 | 2022-04-21 08:17:28 -0700 | [diff] [blame] | 210 | /* Note that PC is advanced for all hardware exceptions. */ |
| 211 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 212 | gen_helper_raise_exception(tcg_env, tcg_constant_i32(index)); |
Richard Henderson | e9150ea | 2021-06-19 21:44:48 -0700 | [diff] [blame] | 213 | dc->base.is_jmp = DISAS_NORETURN; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 214 | } |
| 215 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 216 | static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest) |
| 217 | { |
Richard Henderson | e9150ea | 2021-06-19 21:44:48 -0700 | [diff] [blame] | 218 | const TranslationBlock *tb = dc->base.tb; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 219 | |
Richard Henderson | 6082414 | 2021-06-20 16:24:00 -0700 | [diff] [blame] | 220 | if (translator_use_goto_tb(&dc->base, dest)) { |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 221 | tcg_gen_goto_tb(n); |
Richard Henderson | 17a406e | 2022-04-21 08:16:47 -0700 | [diff] [blame] | 222 | tcg_gen_movi_tl(cpu_pc, dest); |
Richard Henderson | 07ea28b | 2018-05-30 18:06:23 -0700 | [diff] [blame] | 223 | tcg_gen_exit_tb(tb, n); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 224 | } else { |
Richard Henderson | 17a406e | 2022-04-21 08:16:47 -0700 | [diff] [blame] | 225 | tcg_gen_movi_tl(cpu_pc, dest); |
Richard Henderson | 0e6f22c | 2022-04-21 08:17:22 -0700 | [diff] [blame] | 226 | tcg_gen_lookup_and_goto_ptr(); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 227 | } |
Richard Henderson | 3ad5935 | 2022-04-21 08:17:20 -0700 | [diff] [blame] | 228 | dc->base.is_jmp = DISAS_NORETURN; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 229 | } |
| 230 | |
Richard Henderson | bd9154a | 2022-04-21 08:17:19 -0700 | [diff] [blame] | 231 | static void gen_jumpr(DisasContext *dc, int regno, bool is_call) |
| 232 | { |
Richard Henderson | 410c6aa | 2022-04-21 08:17:23 -0700 | [diff] [blame] | 233 | TCGLabel *l = gen_new_label(); |
| 234 | TCGv test = tcg_temp_new(); |
| 235 | TCGv dest = load_gpr(dc, regno); |
| 236 | |
| 237 | tcg_gen_andi_tl(test, dest, 3); |
| 238 | tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l); |
Richard Henderson | 410c6aa | 2022-04-21 08:17:23 -0700 | [diff] [blame] | 239 | |
| 240 | tcg_gen_mov_tl(cpu_pc, dest); |
Richard Henderson | bd9154a | 2022-04-21 08:17:19 -0700 | [diff] [blame] | 241 | if (is_call) { |
| 242 | tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next); |
| 243 | } |
Richard Henderson | 0e6f22c | 2022-04-21 08:17:22 -0700 | [diff] [blame] | 244 | tcg_gen_lookup_and_goto_ptr(); |
Richard Henderson | 410c6aa | 2022-04-21 08:17:23 -0700 | [diff] [blame] | 245 | |
| 246 | gen_set_label(l); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 247 | tcg_gen_st_tl(dest, tcg_env, offsetof(CPUNios2State, ctrl[CR_BADADDR])); |
Richard Henderson | 410c6aa | 2022-04-21 08:17:23 -0700 | [diff] [blame] | 248 | t_gen_helper_raise_exception(dc, EXCP_UNALIGND); |
| 249 | |
Richard Henderson | bd9154a | 2022-04-21 08:17:19 -0700 | [diff] [blame] | 250 | dc->base.is_jmp = DISAS_NORETURN; |
| 251 | } |
| 252 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 253 | static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags) |
| 254 | { |
| 255 | t_gen_helper_raise_exception(dc, flags); |
| 256 | } |
| 257 | |
Richard Henderson | 48b7eac | 2022-04-21 08:16:45 -0700 | [diff] [blame] | 258 | static bool gen_check_supervisor(DisasContext *dc) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 259 | { |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 260 | if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) { |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 261 | /* CPU in user mode, privileged instruction called, stop. */ |
| 262 | t_gen_helper_raise_exception(dc, EXCP_SUPERI); |
Richard Henderson | 48b7eac | 2022-04-21 08:16:45 -0700 | [diff] [blame] | 263 | return false; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 264 | } |
Richard Henderson | 48b7eac | 2022-04-21 08:16:45 -0700 | [diff] [blame] | 265 | return true; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 266 | } |
| 267 | |
| 268 | /* |
| 269 | * Used as a placeholder for all instructions which do not have |
| 270 | * an effect on the simulator (e.g. flush, sync) |
| 271 | */ |
| 272 | static void nop(DisasContext *dc, uint32_t code, uint32_t flags) |
| 273 | { |
| 274 | /* Nothing to do here */ |
| 275 | } |
| 276 | |
| 277 | /* |
| 278 | * J-Type instructions |
| 279 | */ |
| 280 | static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags) |
| 281 | { |
| 282 | J_TYPE(instr, code); |
| 283 | gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 284 | } |
| 285 | |
| 286 | static void call(DisasContext *dc, uint32_t code, uint32_t flags) |
| 287 | { |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 288 | tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 289 | jmpi(dc, code, flags); |
| 290 | } |
| 291 | |
| 292 | /* |
| 293 | * I-Type instructions |
| 294 | */ |
| 295 | /* Load instructions */ |
| 296 | static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags) |
| 297 | { |
| 298 | I_TYPE(instr, code); |
| 299 | |
| 300 | TCGv addr = tcg_temp_new(); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 301 | TCGv data = dest_gpr(dc, instr.b); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 302 | |
Paolo Bonzini | 4ae4b60 | 2017-03-03 17:28:49 +0100 | [diff] [blame] | 303 | tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s); |
Richard Henderson | a978c37 | 2023-05-02 10:38:52 +0100 | [diff] [blame] | 304 | #ifdef CONFIG_USER_ONLY |
| 305 | flags |= MO_UNALN; |
| 306 | #else |
| 307 | flags |= MO_ALIGN; |
| 308 | #endif |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 309 | tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 310 | } |
| 311 | |
| 312 | /* Store instructions */ |
| 313 | static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags) |
| 314 | { |
| 315 | I_TYPE(instr, code); |
| 316 | TCGv val = load_gpr(dc, instr.b); |
| 317 | |
| 318 | TCGv addr = tcg_temp_new(); |
Paolo Bonzini | 4ae4b60 | 2017-03-03 17:28:49 +0100 | [diff] [blame] | 319 | tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s); |
Richard Henderson | a978c37 | 2023-05-02 10:38:52 +0100 | [diff] [blame] | 320 | #ifdef CONFIG_USER_ONLY |
| 321 | flags |= MO_UNALN; |
| 322 | #else |
| 323 | flags |= MO_ALIGN; |
| 324 | #endif |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 325 | tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 326 | } |
| 327 | |
| 328 | /* Branch instructions */ |
| 329 | static void br(DisasContext *dc, uint32_t code, uint32_t flags) |
| 330 | { |
| 331 | I_TYPE(instr, code); |
| 332 | |
Richard Henderson | 77b42a2 | 2021-06-28 14:20:55 -0700 | [diff] [blame] | 333 | gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 334 | } |
| 335 | |
| 336 | static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags) |
| 337 | { |
| 338 | I_TYPE(instr, code); |
| 339 | |
| 340 | TCGLabel *l1 = gen_new_label(); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 341 | tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1); |
Richard Henderson | 77b42a2 | 2021-06-28 14:20:55 -0700 | [diff] [blame] | 342 | gen_goto_tb(dc, 0, dc->base.pc_next); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 343 | gen_set_label(l1); |
Richard Henderson | 77b42a2 | 2021-06-28 14:20:55 -0700 | [diff] [blame] | 344 | gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 345 | } |
| 346 | |
| 347 | /* Comparison instructions */ |
Richard Henderson | 3d1f63d | 2022-04-22 09:16:43 -0700 | [diff] [blame] | 348 | static void do_i_cmpxx(DisasContext *dc, uint32_t insn, |
| 349 | TCGCond cond, ImmFromIType *imm) |
| 350 | { |
| 351 | I_TYPE(instr, insn); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 352 | tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b), |
| 353 | load_gpr(dc, instr.a), imm(&instr)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 354 | } |
| 355 | |
Richard Henderson | 3d1f63d | 2022-04-22 09:16:43 -0700 | [diff] [blame] | 356 | #define gen_i_cmpxx(fname, imm) \ |
| 357 | static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ |
| 358 | { do_i_cmpxx(dc, code, flags, imm); } |
| 359 | |
| 360 | gen_i_cmpxx(gen_cmpxxsi, imm_signed) |
| 361 | gen_i_cmpxx(gen_cmpxxui, imm_unsigned) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 362 | |
| 363 | /* Math/logic instructions */ |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 364 | static void do_i_math_logic(DisasContext *dc, uint32_t insn, |
| 365 | GenFn2i *fn, ImmFromIType *imm, |
| 366 | bool x_op_0_eq_x) |
| 367 | { |
| 368 | I_TYPE(instr, insn); |
| 369 | target_ulong val; |
| 370 | |
| 371 | if (unlikely(instr.b == R_ZERO)) { |
| 372 | /* Store to R_ZERO is ignored -- this catches the canonical NOP. */ |
| 373 | return; |
| 374 | } |
| 375 | |
| 376 | val = imm(&instr); |
| 377 | |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 378 | if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) { |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 379 | /* This catches the canonical expansions of movi and movhi. */ |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 380 | tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0); |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 381 | } else { |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 382 | fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val); |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 383 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 384 | } |
| 385 | |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 386 | #define gen_i_math_logic(fname, insn, x_op_0, imm) \ |
| 387 | static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ |
| 388 | { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 389 | |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 390 | gen_i_math_logic(addi, addi, 1, imm_signed) |
| 391 | gen_i_math_logic(muli, muli, 0, imm_signed) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 392 | |
Richard Henderson | cd419bc | 2022-04-22 09:19:16 -0700 | [diff] [blame] | 393 | gen_i_math_logic(andi, andi, 0, imm_unsigned) |
| 394 | gen_i_math_logic(ori, ori, 1, imm_unsigned) |
| 395 | gen_i_math_logic(xori, xori, 1, imm_unsigned) |
| 396 | |
| 397 | gen_i_math_logic(andhi, andi, 0, imm_shifted) |
| 398 | gen_i_math_logic(orhi , ori, 1, imm_shifted) |
| 399 | gen_i_math_logic(xorhi, xori, 1, imm_shifted) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 400 | |
Richard Henderson | 3a03087 | 2022-04-21 08:17:25 -0700 | [diff] [blame] | 401 | /* rB <- prs.rA + sigma(IMM16) */ |
| 402 | static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags) |
| 403 | { |
| 404 | if (!dc->eic_present) { |
| 405 | t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); |
| 406 | return; |
| 407 | } |
| 408 | if (!gen_check_supervisor(dc)) { |
| 409 | return; |
| 410 | } |
| 411 | |
| 412 | #ifdef CONFIG_USER_ONLY |
| 413 | g_assert_not_reached(); |
| 414 | #else |
| 415 | I_TYPE(instr, code); |
| 416 | TCGv dest = dest_gpr(dc, instr.b); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 417 | gen_helper_rdprs(dest, tcg_env, tcg_constant_i32(instr.a)); |
Richard Henderson | 3a03087 | 2022-04-21 08:17:25 -0700 | [diff] [blame] | 418 | tcg_gen_addi_tl(dest, dest, instr.imm16.s); |
| 419 | #endif |
| 420 | } |
| 421 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 422 | /* Prototype only, defined below */ |
| 423 | static void handle_r_type_instr(DisasContext *dc, uint32_t code, |
| 424 | uint32_t flags); |
| 425 | |
| 426 | static const Nios2Instruction i_type_instructions[] = { |
| 427 | INSTRUCTION(call), /* call */ |
| 428 | INSTRUCTION(jmpi), /* jmpi */ |
| 429 | INSTRUCTION_ILLEGAL(), |
| 430 | INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */ |
| 431 | INSTRUCTION(addi), /* addi */ |
| 432 | INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */ |
| 433 | INSTRUCTION(br), /* br */ |
| 434 | INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */ |
| 435 | INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */ |
| 436 | INSTRUCTION_ILLEGAL(), |
| 437 | INSTRUCTION_ILLEGAL(), |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 438 | INSTRUCTION_FLG(gen_ldx, MO_TEUW), /* ldhu */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 439 | INSTRUCTION(andi), /* andi */ |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 440 | INSTRUCTION_FLG(gen_stx, MO_TEUW), /* sth */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 441 | INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */ |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 442 | INSTRUCTION_FLG(gen_ldx, MO_TESW), /* ldh */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 443 | INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */ |
| 444 | INSTRUCTION_ILLEGAL(), |
| 445 | INSTRUCTION_ILLEGAL(), |
| 446 | INSTRUCTION_NOP(), /* initda */ |
| 447 | INSTRUCTION(ori), /* ori */ |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 448 | INSTRUCTION_FLG(gen_stx, MO_TEUL), /* stw */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 449 | INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */ |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 450 | INSTRUCTION_FLG(gen_ldx, MO_TEUL), /* ldw */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 451 | INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */ |
| 452 | INSTRUCTION_ILLEGAL(), |
| 453 | INSTRUCTION_ILLEGAL(), |
| 454 | INSTRUCTION_NOP(), /* flushda */ |
| 455 | INSTRUCTION(xori), /* xori */ |
| 456 | INSTRUCTION_ILLEGAL(), |
| 457 | INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */ |
| 458 | INSTRUCTION_ILLEGAL(), |
| 459 | INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */ |
| 460 | INSTRUCTION_ILLEGAL(), |
| 461 | INSTRUCTION_ILLEGAL(), |
| 462 | INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */ |
| 463 | INSTRUCTION(muli), /* muli */ |
| 464 | INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */ |
| 465 | INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */ |
| 466 | INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */ |
| 467 | INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */ |
| 468 | INSTRUCTION_ILLEGAL(), |
| 469 | INSTRUCTION_ILLEGAL(), |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 470 | INSTRUCTION_FLG(gen_ldx, MO_TEUW), /* ldhuio */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 471 | INSTRUCTION(andhi), /* andhi */ |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 472 | INSTRUCTION_FLG(gen_stx, MO_TEUW), /* sthio */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 473 | INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */ |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 474 | INSTRUCTION_FLG(gen_ldx, MO_TESW), /* ldhio */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 475 | INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */ |
| 476 | INSTRUCTION_ILLEGAL(), |
| 477 | INSTRUCTION_UNIMPLEMENTED(), /* custom */ |
| 478 | INSTRUCTION_NOP(), /* initd */ |
| 479 | INSTRUCTION(orhi), /* orhi */ |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 480 | INSTRUCTION_FLG(gen_stx, MO_TESL), /* stwio */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 481 | INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */ |
Peter Maydell | 6ab1790 | 2023-06-23 18:25:56 +0100 | [diff] [blame] | 482 | INSTRUCTION_FLG(gen_ldx, MO_TEUL), /* ldwio */ |
Richard Henderson | 3a03087 | 2022-04-21 08:17:25 -0700 | [diff] [blame] | 483 | INSTRUCTION(rdprs), /* rdprs */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 484 | INSTRUCTION_ILLEGAL(), |
| 485 | INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */ |
| 486 | INSTRUCTION_NOP(), /* flushd */ |
| 487 | INSTRUCTION(xorhi), /* xorhi */ |
| 488 | INSTRUCTION_ILLEGAL(), |
| 489 | INSTRUCTION_ILLEGAL(), |
| 490 | INSTRUCTION_ILLEGAL(), |
| 491 | }; |
| 492 | |
| 493 | /* |
| 494 | * R-Type instructions |
| 495 | */ |
| 496 | /* |
| 497 | * status <- estatus |
| 498 | * PC <- ea |
| 499 | */ |
| 500 | static void eret(DisasContext *dc, uint32_t code, uint32_t flags) |
| 501 | { |
Richard Henderson | 48b7eac | 2022-04-21 08:16:45 -0700 | [diff] [blame] | 502 | if (!gen_check_supervisor(dc)) { |
| 503 | return; |
| 504 | } |
Amir Gonnen | b106e7b | 2022-04-21 08:16:44 -0700 | [diff] [blame] | 505 | |
Amir Gonnen | 8d855c8 | 2022-04-21 08:16:48 -0700 | [diff] [blame] | 506 | #ifdef CONFIG_USER_ONLY |
| 507 | g_assert_not_reached(); |
| 508 | #else |
Richard Henderson | 6bcc59c | 2022-04-21 08:17:26 -0700 | [diff] [blame] | 509 | if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { |
| 510 | TCGv tmp = tcg_temp_new(); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 511 | tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS])); |
| 512 | gen_helper_eret(tcg_env, tmp, load_gpr(dc, R_EA)); |
Richard Henderson | 6bcc59c | 2022-04-21 08:17:26 -0700 | [diff] [blame] | 513 | } else { |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 514 | gen_helper_eret(tcg_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA)); |
Richard Henderson | 6bcc59c | 2022-04-21 08:17:26 -0700 | [diff] [blame] | 515 | } |
Amir Gonnen | 8d855c8 | 2022-04-21 08:16:48 -0700 | [diff] [blame] | 516 | dc->base.is_jmp = DISAS_NORETURN; |
| 517 | #endif |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 518 | } |
| 519 | |
| 520 | /* PC <- ra */ |
| 521 | static void ret(DisasContext *dc, uint32_t code, uint32_t flags) |
| 522 | { |
Richard Henderson | bd9154a | 2022-04-21 08:17:19 -0700 | [diff] [blame] | 523 | gen_jumpr(dc, R_RA, false); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 524 | } |
| 525 | |
Richard Henderson | 48da43b | 2022-04-21 08:16:49 -0700 | [diff] [blame] | 526 | /* |
| 527 | * status <- bstatus |
| 528 | * PC <- ba |
| 529 | */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 530 | static void bret(DisasContext *dc, uint32_t code, uint32_t flags) |
| 531 | { |
Richard Henderson | 48da43b | 2022-04-21 08:16:49 -0700 | [diff] [blame] | 532 | if (!gen_check_supervisor(dc)) { |
| 533 | return; |
| 534 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 535 | |
Richard Henderson | 48da43b | 2022-04-21 08:16:49 -0700 | [diff] [blame] | 536 | #ifdef CONFIG_USER_ONLY |
| 537 | g_assert_not_reached(); |
| 538 | #else |
Richard Henderson | f1ec078 | 2022-04-21 08:16:50 -0700 | [diff] [blame] | 539 | TCGv tmp = tcg_temp_new(); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 540 | tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS])); |
| 541 | gen_helper_eret(tcg_env, tmp, load_gpr(dc, R_BA)); |
Richard Henderson | f1ec078 | 2022-04-21 08:16:50 -0700 | [diff] [blame] | 542 | |
Richard Henderson | 48da43b | 2022-04-21 08:16:49 -0700 | [diff] [blame] | 543 | dc->base.is_jmp = DISAS_NORETURN; |
| 544 | #endif |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 545 | } |
| 546 | |
| 547 | /* PC <- rA */ |
| 548 | static void jmp(DisasContext *dc, uint32_t code, uint32_t flags) |
| 549 | { |
| 550 | R_TYPE(instr, code); |
| 551 | |
Richard Henderson | bd9154a | 2022-04-21 08:17:19 -0700 | [diff] [blame] | 552 | gen_jumpr(dc, instr.a, false); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 553 | } |
| 554 | |
| 555 | /* rC <- PC + 4 */ |
| 556 | static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags) |
| 557 | { |
| 558 | R_TYPE(instr, code); |
| 559 | |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 560 | tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 561 | } |
| 562 | |
| 563 | /* |
| 564 | * ra <- PC + 4 |
| 565 | * PC <- rA |
| 566 | */ |
| 567 | static void callr(DisasContext *dc, uint32_t code, uint32_t flags) |
| 568 | { |
| 569 | R_TYPE(instr, code); |
| 570 | |
Richard Henderson | bd9154a | 2022-04-21 08:17:19 -0700 | [diff] [blame] | 571 | gen_jumpr(dc, instr.a, true); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 572 | } |
| 573 | |
| 574 | /* rC <- ctlN */ |
| 575 | static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags) |
| 576 | { |
Richard Henderson | 48b7eac | 2022-04-21 08:16:45 -0700 | [diff] [blame] | 577 | if (!gen_check_supervisor(dc)) { |
| 578 | return; |
| 579 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 580 | |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 581 | #ifdef CONFIG_USER_ONLY |
| 582 | g_assert_not_reached(); |
| 583 | #else |
| 584 | R_TYPE(instr, code); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 585 | TCGv t1, t2, dest = dest_gpr(dc, instr.c); |
Richard Henderson | 0b6e8f5 | 2022-02-26 01:06:07 -1000 | [diff] [blame] | 586 | |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 587 | /* Reserved registers read as zero. */ |
| 588 | if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) { |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 589 | tcg_gen_movi_tl(dest, 0); |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 590 | return; |
| 591 | } |
| 592 | |
Richard Henderson | b8f036a | 2022-04-21 08:16:53 -0700 | [diff] [blame] | 593 | switch (instr.imm5) { |
Richard Henderson | 8d8d73b | 2022-02-26 01:29:42 -1000 | [diff] [blame] | 594 | case CR_IPENDING: |
| 595 | /* |
| 596 | * The value of the ipending register is synthetic. |
| 597 | * In hw, this is the AND of a set of hardware irq lines |
| 598 | * with the ienable register. In qemu, we re-use the space |
| 599 | * of CR_IPENDING to store the set of irq lines, and so we |
| 600 | * must perform the AND here, and anywhere else we need the |
| 601 | * guest value of ipending. |
| 602 | */ |
Richard Henderson | f1ec078 | 2022-04-21 08:16:50 -0700 | [diff] [blame] | 603 | t1 = tcg_temp_new(); |
| 604 | t2 = tcg_temp_new(); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 605 | tcg_gen_ld_tl(t1, tcg_env, offsetof(CPUNios2State, ctrl[CR_IPENDING])); |
| 606 | tcg_gen_ld_tl(t2, tcg_env, offsetof(CPUNios2State, ctrl[CR_IENABLE])); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 607 | tcg_gen_and_tl(dest, t1, t2); |
Richard Henderson | 8d8d73b | 2022-02-26 01:29:42 -1000 | [diff] [blame] | 608 | break; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 609 | default: |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 610 | tcg_gen_ld_tl(dest, tcg_env, |
Richard Henderson | b8f036a | 2022-04-21 08:16:53 -0700 | [diff] [blame] | 611 | offsetof(CPUNios2State, ctrl[instr.imm5])); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 612 | break; |
| 613 | } |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 614 | #endif |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 615 | } |
| 616 | |
| 617 | /* ctlN <- rA */ |
| 618 | static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) |
| 619 | { |
Richard Henderson | 48b7eac | 2022-04-21 08:16:45 -0700 | [diff] [blame] | 620 | if (!gen_check_supervisor(dc)) { |
| 621 | return; |
| 622 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 623 | |
Richard Henderson | 48b7eac | 2022-04-21 08:16:45 -0700 | [diff] [blame] | 624 | #ifdef CONFIG_USER_ONLY |
| 625 | g_assert_not_reached(); |
| 626 | #else |
Richard Henderson | 304c05d | 2022-02-26 01:27:32 -1000 | [diff] [blame] | 627 | R_TYPE(instr, code); |
| 628 | TCGv v = load_gpr(dc, instr.a); |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 629 | uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]); |
| 630 | uint32_t wr = dc->cr_state[instr.imm5].writable; |
| 631 | uint32_t ro = dc->cr_state[instr.imm5].readonly; |
| 632 | |
| 633 | /* Skip reserved or readonly registers. */ |
| 634 | if (wr == 0) { |
| 635 | return; |
| 636 | } |
Richard Henderson | 304c05d | 2022-02-26 01:27:32 -1000 | [diff] [blame] | 637 | |
Richard Henderson | b8f036a | 2022-04-21 08:16:53 -0700 | [diff] [blame] | 638 | switch (instr.imm5) { |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 639 | case CR_PTEADDR: |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 640 | gen_helper_mmu_write_pteaddr(tcg_env, v); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 641 | break; |
Richard Henderson | 304c05d | 2022-02-26 01:27:32 -1000 | [diff] [blame] | 642 | case CR_TLBACC: |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 643 | gen_helper_mmu_write_tlbacc(tcg_env, v); |
Richard Henderson | 304c05d | 2022-02-26 01:27:32 -1000 | [diff] [blame] | 644 | break; |
| 645 | case CR_TLBMISC: |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 646 | gen_helper_mmu_write_tlbmisc(tcg_env, v); |
Richard Henderson | 304c05d | 2022-02-26 01:27:32 -1000 | [diff] [blame] | 647 | break; |
Richard Henderson | b72c9d5 | 2022-02-26 01:56:15 -1000 | [diff] [blame] | 648 | case CR_STATUS: |
| 649 | case CR_IENABLE: |
| 650 | /* If interrupts were enabled using WRCTL, trigger them. */ |
| 651 | dc->base.is_jmp = DISAS_UPDATE; |
| 652 | /* fall through */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 653 | default: |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 654 | if (wr == -1) { |
| 655 | /* The register is entirely writable. */ |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 656 | tcg_gen_st_tl(v, tcg_env, ofs); |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 657 | } else { |
| 658 | /* |
| 659 | * The register is partially read-only or reserved: |
| 660 | * merge the value. |
| 661 | */ |
| 662 | TCGv n = tcg_temp_new(); |
| 663 | |
| 664 | tcg_gen_andi_tl(n, v, wr); |
| 665 | |
| 666 | if (ro != 0) { |
| 667 | TCGv o = tcg_temp_new(); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 668 | tcg_gen_ld_tl(o, tcg_env, ofs); |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 669 | tcg_gen_andi_tl(o, o, ro); |
| 670 | tcg_gen_or_tl(n, n, o); |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 671 | } |
| 672 | |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 673 | tcg_gen_st_tl(n, tcg_env, ofs); |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 674 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 675 | break; |
| 676 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 677 | #endif |
| 678 | } |
| 679 | |
Richard Henderson | 3a03087 | 2022-04-21 08:17:25 -0700 | [diff] [blame] | 680 | /* prs.rC <- rA */ |
| 681 | static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags) |
| 682 | { |
| 683 | if (!dc->eic_present) { |
| 684 | t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); |
| 685 | return; |
| 686 | } |
| 687 | if (!gen_check_supervisor(dc)) { |
| 688 | return; |
| 689 | } |
| 690 | |
| 691 | #ifdef CONFIG_USER_ONLY |
| 692 | g_assert_not_reached(); |
| 693 | #else |
| 694 | R_TYPE(instr, code); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 695 | gen_helper_wrprs(tcg_env, tcg_constant_i32(instr.c), |
Richard Henderson | 3a03087 | 2022-04-21 08:17:25 -0700 | [diff] [blame] | 696 | load_gpr(dc, instr.a)); |
| 697 | /* |
| 698 | * The expected write to PRS[r0] is 0, from CRS[r0]. |
| 699 | * If not, and CRS == PRS (which we cannot tell from here), |
| 700 | * we may now have a non-zero value in our current r0. |
| 701 | * By ending the TB, we re-evaluate tb_flags and find out. |
| 702 | */ |
| 703 | if (instr.c == 0 |
| 704 | && (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) { |
| 705 | dc->base.is_jmp = DISAS_UPDATE; |
| 706 | } |
| 707 | #endif |
| 708 | } |
| 709 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 710 | /* Comparison instructions */ |
| 711 | static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags) |
| 712 | { |
| 713 | R_TYPE(instr, code); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 714 | tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c), |
| 715 | load_gpr(dc, instr.a), load_gpr(dc, instr.b)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 716 | } |
| 717 | |
| 718 | /* Math/logic instructions */ |
Richard Henderson | 7c84904 | 2022-04-22 09:25:30 -0700 | [diff] [blame] | 719 | static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn) |
| 720 | { |
| 721 | R_TYPE(instr, insn); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 722 | fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 723 | } |
| 724 | |
Richard Henderson | 7c84904 | 2022-04-22 09:25:30 -0700 | [diff] [blame] | 725 | static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn) |
| 726 | { |
| 727 | R_TYPE(instr, insn); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 728 | fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b)); |
Richard Henderson | 7c84904 | 2022-04-22 09:25:30 -0700 | [diff] [blame] | 729 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 730 | |
Richard Henderson | 7c84904 | 2022-04-22 09:25:30 -0700 | [diff] [blame] | 731 | #define gen_ri_math_logic(fname, insn) \ |
| 732 | static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ |
| 733 | { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); } |
| 734 | |
| 735 | #define gen_rr_math_logic(fname, insn) \ |
| 736 | static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ |
| 737 | { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); } |
| 738 | |
| 739 | gen_rr_math_logic(add, add) |
| 740 | gen_rr_math_logic(sub, sub) |
| 741 | gen_rr_math_logic(mul, mul) |
| 742 | |
| 743 | gen_rr_math_logic(and, and) |
| 744 | gen_rr_math_logic(or, or) |
| 745 | gen_rr_math_logic(xor, xor) |
| 746 | gen_rr_math_logic(nor, nor) |
| 747 | |
| 748 | gen_ri_math_logic(srai, sari) |
| 749 | gen_ri_math_logic(srli, shri) |
| 750 | gen_ri_math_logic(slli, shli) |
| 751 | gen_ri_math_logic(roli, rotli) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 752 | |
Richard Henderson | 3099c41 | 2022-04-22 09:28:38 -0700 | [diff] [blame] | 753 | static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn) |
| 754 | { |
| 755 | R_TYPE(instr, insn); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 756 | TCGv discard = tcg_temp_new(); |
Richard Henderson | 3099c41 | 2022-04-22 09:28:38 -0700 | [diff] [blame] | 757 | |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 758 | fn(discard, dest_gpr(dc, instr.c), |
| 759 | load_gpr(dc, instr.a), load_gpr(dc, instr.b)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 760 | } |
| 761 | |
Richard Henderson | 3099c41 | 2022-04-22 09:28:38 -0700 | [diff] [blame] | 762 | #define gen_rr_mul_high(fname, insn) \ |
| 763 | static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ |
| 764 | { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); } |
| 765 | |
| 766 | gen_rr_mul_high(mulxss, muls2) |
| 767 | gen_rr_mul_high(mulxuu, mulu2) |
| 768 | gen_rr_mul_high(mulxsu, mulsu2) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 769 | |
Richard Henderson | 541cb62 | 2022-04-22 09:32:26 -0700 | [diff] [blame] | 770 | static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn) |
| 771 | { |
| 772 | R_TYPE(instr, insn); |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 773 | TCGv sh = tcg_temp_new(); |
Richard Henderson | 541cb62 | 2022-04-22 09:32:26 -0700 | [diff] [blame] | 774 | |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 775 | tcg_gen_andi_tl(sh, load_gpr(dc, instr.b), 31); |
| 776 | fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), sh); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 777 | } |
| 778 | |
Richard Henderson | 541cb62 | 2022-04-22 09:32:26 -0700 | [diff] [blame] | 779 | #define gen_rr_shift(fname, insn) \ |
| 780 | static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ |
| 781 | { do_rr_shift(dc, code, tcg_gen_##insn##_tl); } |
| 782 | |
| 783 | gen_rr_shift(sra, sar) |
| 784 | gen_rr_shift(srl, shr) |
| 785 | gen_rr_shift(sll, shl) |
| 786 | gen_rr_shift(rol, rotl) |
| 787 | gen_rr_shift(ror, rotr) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 788 | |
| 789 | static void divs(DisasContext *dc, uint32_t code, uint32_t flags) |
| 790 | { |
| 791 | R_TYPE(instr, (code)); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 792 | gen_helper_divs(dest_gpr(dc, instr.c), tcg_env, |
Richard Henderson | 345b7a8 | 2022-04-21 08:17:12 -0700 | [diff] [blame] | 793 | load_gpr(dc, instr.a), load_gpr(dc, instr.b)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 794 | } |
| 795 | |
| 796 | static void divu(DisasContext *dc, uint32_t code, uint32_t flags) |
| 797 | { |
| 798 | R_TYPE(instr, (code)); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 799 | gen_helper_divu(dest_gpr(dc, instr.c), tcg_env, |
Richard Henderson | 345b7a8 | 2022-04-21 08:17:12 -0700 | [diff] [blame] | 800 | load_gpr(dc, instr.a), load_gpr(dc, instr.b)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 801 | } |
| 802 | |
Richard Henderson | 87d7bfd | 2021-12-20 18:50:06 -0800 | [diff] [blame] | 803 | static void trap(DisasContext *dc, uint32_t code, uint32_t flags) |
| 804 | { |
| 805 | #ifdef CONFIG_USER_ONLY |
| 806 | /* |
| 807 | * The imm5 field is not stored anywhere on real hw; the kernel |
| 808 | * has to load the insn and extract the field. But we can make |
| 809 | * things easier for cpu_loop if we pop this into env->error_code. |
| 810 | */ |
| 811 | R_TYPE(instr, code); |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 812 | tcg_gen_st_i32(tcg_constant_i32(instr.imm5), tcg_env, |
Richard Henderson | 87d7bfd | 2021-12-20 18:50:06 -0800 | [diff] [blame] | 813 | offsetof(CPUNios2State, error_code)); |
| 814 | #endif |
| 815 | t_gen_helper_raise_exception(dc, EXCP_TRAP); |
| 816 | } |
| 817 | |
Richard Henderson | 24ca313 | 2022-04-21 08:17:02 -0700 | [diff] [blame] | 818 | static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags) |
| 819 | { |
| 820 | #ifndef CONFIG_USER_ONLY |
| 821 | /* The semihosting instruction is "break 1". */ |
Peter Maydell | cab9f19 | 2022-08-22 15:12:28 +0100 | [diff] [blame] | 822 | bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U); |
Richard Henderson | 24ca313 | 2022-04-21 08:17:02 -0700 | [diff] [blame] | 823 | R_TYPE(instr, code); |
Peter Maydell | cab9f19 | 2022-08-22 15:12:28 +0100 | [diff] [blame] | 824 | if (semihosting_enabled(is_user) && instr.imm5 == 1) { |
Richard Henderson | 24ca313 | 2022-04-21 08:17:02 -0700 | [diff] [blame] | 825 | t_gen_helper_raise_exception(dc, EXCP_SEMIHOST); |
| 826 | return; |
| 827 | } |
| 828 | #endif |
| 829 | |
| 830 | t_gen_helper_raise_exception(dc, EXCP_BREAK); |
| 831 | } |
| 832 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 833 | static const Nios2Instruction r_type_instructions[] = { |
| 834 | INSTRUCTION_ILLEGAL(), |
| 835 | INSTRUCTION(eret), /* eret */ |
| 836 | INSTRUCTION(roli), /* roli */ |
| 837 | INSTRUCTION(rol), /* rol */ |
| 838 | INSTRUCTION_NOP(), /* flushp */ |
| 839 | INSTRUCTION(ret), /* ret */ |
| 840 | INSTRUCTION(nor), /* nor */ |
| 841 | INSTRUCTION(mulxuu), /* mulxuu */ |
| 842 | INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */ |
| 843 | INSTRUCTION(bret), /* bret */ |
| 844 | INSTRUCTION_ILLEGAL(), |
| 845 | INSTRUCTION(ror), /* ror */ |
| 846 | INSTRUCTION_NOP(), /* flushi */ |
| 847 | INSTRUCTION(jmp), /* jmp */ |
| 848 | INSTRUCTION(and), /* and */ |
| 849 | INSTRUCTION_ILLEGAL(), |
| 850 | INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */ |
| 851 | INSTRUCTION_ILLEGAL(), |
| 852 | INSTRUCTION(slli), /* slli */ |
| 853 | INSTRUCTION(sll), /* sll */ |
Richard Henderson | 3a03087 | 2022-04-21 08:17:25 -0700 | [diff] [blame] | 854 | INSTRUCTION(wrprs), /* wrprs */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 855 | INSTRUCTION_ILLEGAL(), |
| 856 | INSTRUCTION(or), /* or */ |
| 857 | INSTRUCTION(mulxsu), /* mulxsu */ |
| 858 | INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */ |
| 859 | INSTRUCTION_ILLEGAL(), |
| 860 | INSTRUCTION(srli), /* srli */ |
| 861 | INSTRUCTION(srl), /* srl */ |
| 862 | INSTRUCTION(nextpc), /* nextpc */ |
| 863 | INSTRUCTION(callr), /* callr */ |
| 864 | INSTRUCTION(xor), /* xor */ |
| 865 | INSTRUCTION(mulxss), /* mulxss */ |
| 866 | INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */ |
| 867 | INSTRUCTION_ILLEGAL(), |
| 868 | INSTRUCTION_ILLEGAL(), |
| 869 | INSTRUCTION_ILLEGAL(), |
| 870 | INSTRUCTION(divu), /* divu */ |
| 871 | INSTRUCTION(divs), /* div */ |
| 872 | INSTRUCTION(rdctl), /* rdctl */ |
| 873 | INSTRUCTION(mul), /* mul */ |
| 874 | INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */ |
| 875 | INSTRUCTION_NOP(), /* initi */ |
| 876 | INSTRUCTION_ILLEGAL(), |
| 877 | INSTRUCTION_ILLEGAL(), |
| 878 | INSTRUCTION_ILLEGAL(), |
Richard Henderson | 87d7bfd | 2021-12-20 18:50:06 -0800 | [diff] [blame] | 879 | INSTRUCTION(trap), /* trap */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 880 | INSTRUCTION(wrctl), /* wrctl */ |
| 881 | INSTRUCTION_ILLEGAL(), |
| 882 | INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */ |
| 883 | INSTRUCTION(add), /* add */ |
| 884 | INSTRUCTION_ILLEGAL(), |
| 885 | INSTRUCTION_ILLEGAL(), |
Richard Henderson | 24ca313 | 2022-04-21 08:17:02 -0700 | [diff] [blame] | 886 | INSTRUCTION(gen_break), /* break */ |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 887 | INSTRUCTION_ILLEGAL(), |
| 888 | INSTRUCTION(nop), /* nop */ |
| 889 | INSTRUCTION_ILLEGAL(), |
| 890 | INSTRUCTION_ILLEGAL(), |
| 891 | INSTRUCTION(sub), /* sub */ |
| 892 | INSTRUCTION(srai), /* srai */ |
| 893 | INSTRUCTION(sra), /* sra */ |
| 894 | INSTRUCTION_ILLEGAL(), |
| 895 | INSTRUCTION_ILLEGAL(), |
| 896 | INSTRUCTION_ILLEGAL(), |
| 897 | INSTRUCTION_ILLEGAL(), |
| 898 | }; |
| 899 | |
| 900 | static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags) |
| 901 | { |
| 902 | uint8_t opx; |
| 903 | const Nios2Instruction *instr; |
| 904 | |
| 905 | opx = get_opxcode(code); |
| 906 | if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) { |
| 907 | goto illegal_op; |
| 908 | } |
| 909 | |
| 910 | instr = &r_type_instructions[opx]; |
| 911 | instr->handler(dc, code, instr->flags); |
| 912 | |
| 913 | return; |
| 914 | |
| 915 | illegal_op: |
| 916 | t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); |
| 917 | } |
| 918 | |
Richard Henderson | b8f036a | 2022-04-21 08:16:53 -0700 | [diff] [blame] | 919 | static const char * const gr_regnames[NUM_GP_REGS] = { |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 920 | "zero", "at", "r2", "r3", |
| 921 | "r4", "r5", "r6", "r7", |
| 922 | "r8", "r9", "r10", "r11", |
| 923 | "r12", "r13", "r14", "r15", |
| 924 | "r16", "r17", "r18", "r19", |
| 925 | "r20", "r21", "r22", "r23", |
| 926 | "et", "bt", "gp", "sp", |
| 927 | "fp", "ea", "ba", "ra", |
Richard Henderson | b8f036a | 2022-04-21 08:16:53 -0700 | [diff] [blame] | 928 | }; |
| 929 | |
Richard Henderson | 5dfb910 | 2022-04-21 08:16:54 -0700 | [diff] [blame] | 930 | #ifndef CONFIG_USER_ONLY |
Richard Henderson | b8f036a | 2022-04-21 08:16:53 -0700 | [diff] [blame] | 931 | static const char * const cr_regnames[NUM_CR_REGS] = { |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 932 | "status", "estatus", "bstatus", "ienable", |
Richard Henderson | 5dfb910 | 2022-04-21 08:16:54 -0700 | [diff] [blame] | 933 | "ipending", "cpuid", "res6", "exception", |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 934 | "pteaddr", "tlbacc", "tlbmisc", "reserved1", |
| 935 | "badaddr", "config", "mpubase", "mpuacc", |
Richard Henderson | 5dfb910 | 2022-04-21 08:16:54 -0700 | [diff] [blame] | 936 | "res16", "res17", "res18", "res19", |
| 937 | "res20", "res21", "res22", "res23", |
| 938 | "res24", "res25", "res26", "res27", |
| 939 | "res28", "res29", "res30", "res31", |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 940 | }; |
Richard Henderson | 5dfb910 | 2022-04-21 08:16:54 -0700 | [diff] [blame] | 941 | #endif |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 942 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 943 | /* generate intermediate code for basic block 'tb'. */ |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 944 | static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 945 | { |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 946 | DisasContext *dc = container_of(dcbase, DisasContext, base); |
Richard Henderson | b77af26 | 2023-09-13 17:22:49 -0700 | [diff] [blame] | 947 | CPUNios2State *env = cpu_env(cs); |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 948 | Nios2CPU *cpu = env_archcpu(env); |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 949 | int page_insns; |
Richard Henderson | e9150ea | 2021-06-19 21:44:48 -0700 | [diff] [blame] | 950 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 951 | dc->mem_idx = cpu_mmu_index(env, false); |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 952 | dc->cr_state = cpu->cr_state; |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 953 | dc->tb_flags = dc->base.tb->flags; |
Richard Henderson | 3a03087 | 2022-04-21 08:17:25 -0700 | [diff] [blame] | 954 | dc->eic_present = cpu->eic_present; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 955 | |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 956 | /* Bound the number of insns to execute to those left on the page. */ |
| 957 | page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; |
| 958 | dc->base.max_insns = MIN(page_insns, dc->base.max_insns); |
| 959 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 960 | |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 961 | static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs) |
| 962 | { |
| 963 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 964 | |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 965 | static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) |
| 966 | { |
| 967 | tcg_gen_insn_start(dcbase->pc_next); |
| 968 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 969 | |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 970 | static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) |
| 971 | { |
| 972 | DisasContext *dc = container_of(dcbase, DisasContext, base); |
Richard Henderson | b77af26 | 2023-09-13 17:22:49 -0700 | [diff] [blame] | 973 | CPUNios2State *env = cpu_env(cs); |
Richard Henderson | 1ff375d | 2021-06-28 14:04:24 -0700 | [diff] [blame] | 974 | const Nios2Instruction *instr; |
| 975 | uint32_t code, pc; |
| 976 | uint8_t op; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 977 | |
Richard Henderson | 1ff375d | 2021-06-28 14:04:24 -0700 | [diff] [blame] | 978 | pc = dc->base.pc_next; |
| 979 | dc->pc = pc; |
| 980 | dc->base.pc_next = pc + 4; |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 981 | |
| 982 | /* Decode an instruction */ |
Richard Henderson | 1ff375d | 2021-06-28 14:04:24 -0700 | [diff] [blame] | 983 | code = cpu_ldl_code(env, pc); |
| 984 | op = get_opcode(code); |
| 985 | |
| 986 | if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) { |
| 987 | t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); |
| 988 | return; |
| 989 | } |
| 990 | |
Richard Henderson | 7eed8e4 | 2022-04-21 08:17:16 -0700 | [diff] [blame] | 991 | dc->sink = NULL; |
| 992 | |
Richard Henderson | 1ff375d | 2021-06-28 14:04:24 -0700 | [diff] [blame] | 993 | instr = &i_type_instructions[op]; |
| 994 | instr->handler(dc, code, instr->flags); |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 995 | } |
| 996 | |
| 997 | static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) |
| 998 | { |
| 999 | DisasContext *dc = container_of(dcbase, DisasContext, base); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1000 | |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1001 | /* Indicate where the next block should start */ |
Richard Henderson | e9150ea | 2021-06-19 21:44:48 -0700 | [diff] [blame] | 1002 | switch (dc->base.is_jmp) { |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 1003 | case DISAS_TOO_MANY: |
Richard Henderson | 5b84328 | 2022-04-21 08:17:21 -0700 | [diff] [blame] | 1004 | gen_goto_tb(dc, 0, dc->base.pc_next); |
| 1005 | break; |
| 1006 | |
Wentong Wu | c769453 | 2020-07-13 14:36:10 +0100 | [diff] [blame] | 1007 | case DISAS_UPDATE: |
Richard Henderson | 5b84328 | 2022-04-21 08:17:21 -0700 | [diff] [blame] | 1008 | /* Save the current PC, and return to the main loop. */ |
Richard Henderson | 17a406e | 2022-04-21 08:16:47 -0700 | [diff] [blame] | 1009 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); |
Richard Henderson | 07ea28b | 2018-05-30 18:06:23 -0700 | [diff] [blame] | 1010 | tcg_gen_exit_tb(NULL, 0); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1011 | break; |
| 1012 | |
Wentong Wu | 42928f2 | 2020-07-13 14:36:10 +0100 | [diff] [blame] | 1013 | case DISAS_NORETURN: |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1014 | /* nothing more to generate */ |
| 1015 | break; |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 1016 | |
| 1017 | default: |
| 1018 | g_assert_not_reached(); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1019 | } |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 1020 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1021 | |
Richard Henderson | 8eb806a | 2022-04-17 11:29:52 -0700 | [diff] [blame] | 1022 | static void nios2_tr_disas_log(const DisasContextBase *dcbase, |
| 1023 | CPUState *cpu, FILE *logfile) |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 1024 | { |
Richard Henderson | 8eb806a | 2022-04-17 11:29:52 -0700 | [diff] [blame] | 1025 | fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); |
| 1026 | target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 1027 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1028 | |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 1029 | static const TranslatorOps nios2_tr_ops = { |
| 1030 | .init_disas_context = nios2_tr_init_disas_context, |
| 1031 | .tb_start = nios2_tr_tb_start, |
| 1032 | .insn_start = nios2_tr_insn_start, |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 1033 | .translate_insn = nios2_tr_translate_insn, |
| 1034 | .tb_stop = nios2_tr_tb_stop, |
| 1035 | .disas_log = nios2_tr_disas_log, |
| 1036 | }; |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1037 | |
Richard Henderson | 597f9b2 | 2023-01-28 15:19:22 -1000 | [diff] [blame] | 1038 | void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, |
Richard Henderson | 306c872 | 2022-08-11 13:48:03 -0700 | [diff] [blame] | 1039 | target_ulong pc, void *host_pc) |
Richard Henderson | d67cbd9 | 2021-06-19 22:12:17 -0700 | [diff] [blame] | 1040 | { |
| 1041 | DisasContext dc; |
Richard Henderson | 306c872 | 2022-08-11 13:48:03 -0700 | [diff] [blame] | 1042 | translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1043 | } |
| 1044 | |
Markus Armbruster | 90c84c5 | 2019-04-17 21:18:02 +0200 | [diff] [blame] | 1045 | void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags) |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1046 | { |
| 1047 | Nios2CPU *cpu = NIOS2_CPU(cs); |
| 1048 | CPUNios2State *env = &cpu->env; |
| 1049 | int i; |
| 1050 | |
Richard Henderson | 17a406e | 2022-04-21 08:16:47 -0700 | [diff] [blame] | 1051 | qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1052 | |
Richard Henderson | b8f036a | 2022-04-21 08:16:53 -0700 | [diff] [blame] | 1053 | for (i = 0; i < NUM_GP_REGS; i++) { |
| 1054 | qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]); |
| 1055 | if ((i + 1) % 4 == 0) { |
| 1056 | qemu_fprintf(f, "\n"); |
| 1057 | } |
| 1058 | } |
Richard Henderson | 5dfb910 | 2022-04-21 08:16:54 -0700 | [diff] [blame] | 1059 | |
| 1060 | #if !defined(CONFIG_USER_ONLY) |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 1061 | int j; |
| 1062 | |
| 1063 | for (i = j = 0; i < NUM_CR_REGS; i++) { |
| 1064 | if (!nios2_cr_reserved(&cpu->cr_state[i])) { |
| 1065 | qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]); |
| 1066 | if (++j % 4 == 0) { |
| 1067 | qemu_fprintf(f, "\n"); |
| 1068 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1069 | } |
| 1070 | } |
Richard Henderson | 796945d | 2022-04-21 08:17:08 -0700 | [diff] [blame] | 1071 | if (j % 4 != 0) { |
| 1072 | qemu_fprintf(f, "\n"); |
| 1073 | } |
| 1074 | if (cpu->mmu_present) { |
| 1075 | qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n", |
| 1076 | env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK, |
| 1077 | FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID), |
| 1078 | env->mmu.tlbacc_wr); |
| 1079 | } |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1080 | #endif |
Markus Armbruster | 90c84c5 | 2019-04-17 21:18:02 +0200 | [diff] [blame] | 1081 | qemu_fprintf(f, "\n\n"); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1082 | } |
| 1083 | |
| 1084 | void nios2_tcg_init(void) |
| 1085 | { |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 1086 | #ifndef CONFIG_USER_ONLY |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 1087 | TCGv_ptr crs = tcg_global_mem_new_ptr(tcg_env, |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 1088 | offsetof(CPUNios2State, regs), "crs"); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1089 | |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 1090 | for (int i = 0; i < NUM_GP_REGS; i++) { |
| 1091 | cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]); |
| 1092 | } |
| 1093 | |
| 1094 | #define offsetof_regs0(N) offsetof(CPUNios2State, shadow_regs[0][N]) |
| 1095 | #else |
| 1096 | #define offsetof_regs0(N) offsetof(CPUNios2State, regs[N]) |
| 1097 | #endif |
| 1098 | |
| 1099 | for (int i = 0; i < NUM_GP_REGS; i++) { |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 1100 | cpu_R[i] = tcg_global_mem_new(tcg_env, offsetof_regs0(i), |
Richard Henderson | b8f036a | 2022-04-21 08:16:53 -0700 | [diff] [blame] | 1101 | gr_regnames[i]); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1102 | } |
Richard Henderson | 945a5bd | 2022-04-21 08:17:24 -0700 | [diff] [blame] | 1103 | |
| 1104 | #undef offsetof_regs0 |
| 1105 | |
Richard Henderson | ad75a51 | 2023-09-13 16:37:36 -0700 | [diff] [blame] | 1106 | cpu_pc = tcg_global_mem_new(tcg_env, |
Richard Henderson | 17a406e | 2022-04-21 08:16:47 -0700 | [diff] [blame] | 1107 | offsetof(CPUNios2State, pc), "pc"); |
Chris Wulff | 032c76b | 2017-01-18 23:01:41 +0100 | [diff] [blame] | 1108 | } |