blob: e80662359468abfe32d5484781f5fcdc9d1df0fb [file] [log] [blame]
Chris Wulff032c76b2017-01-18 23:01:41 +01001/*
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é9d808652017-10-17 13:44:01 -030024#include "qemu/osdep.h"
Chris Wulff032c76b2017-01-18 23:01:41 +010025#include "cpu.h"
Philippe Mathieu-Daudédcb32f12020-01-01 12:23:00 +010026#include "tcg/tcg-op.h"
Chris Wulff032c76b2017-01-18 23:01:41 +010027#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 Vilanova77fc6f52017-07-14 11:21:37 +030032#include "exec/translator.h"
Markus Armbruster90c84c52019-04-17 21:18:02 +020033#include "qemu/qemu-print.h"
Richard Henderson24ca3132022-04-21 08:17:02 -070034#include "semihosting/semihost.h"
Lluís Vilanova77fc6f52017-07-14 11:21:37 +030035
Richard Hendersond53106c2023-03-31 10:37:04 -070036#define HELPER_H "helper.h"
37#include "exec/helper-info.c.inc"
38#undef HELPER_H
39
40
Lluís Vilanova77fc6f52017-07-14 11:21:37 +030041/* is_jmp field values */
Lluís Vilanova77fc6f52017-07-14 11:21:37 +030042#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
Chris Wulff032c76b2017-01-18 23:01:41 +010043
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 Henderson17463382022-04-21 08:17:14 -070058typedef 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 Wulff032c76b2017-01-18 23:01:41 +010068#define I_TYPE(instr, code) \
Richard Henderson17463382022-04-21 08:17:14 -070069 InstrIType (instr) = { \
Chris Wulff032c76b2017-01-18 23:01:41 +010070 .op = extract32((code), 0, 6), \
Paolo Bonzini4ae4b602017-03-03 17:28:49 +010071 .imm16.u = extract32((code), 6, 16), \
Chris Wulff032c76b2017-01-18 23:01:41 +010072 .b = extract32((code), 22, 5), \
73 .a = extract32((code), 27, 5), \
74 }
75
Richard Henderson3d1f63d2022-04-22 09:16:43 -070076typedef target_ulong ImmFromIType(const InstrIType *);
77
78static target_ulong imm_unsigned(const InstrIType *i)
79{
80 return i->imm16.u;
81}
82
83static target_ulong imm_signed(const InstrIType *i)
84{
85 return i->imm16.s;
86}
87
Richard Hendersoncd419bc2022-04-22 09:19:16 -070088static target_ulong imm_shifted(const InstrIType *i)
89{
90 return i->imm16.u << 16;
91}
92
Chris Wulff032c76b2017-01-18 23:01:41 +010093/* R-Type instruction parsing */
Richard Henderson17463382022-04-21 08:17:14 -070094typedef 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 Wulff032c76b2017-01-18 23:01:41 +0100103#define R_TYPE(instr, code) \
Richard Henderson17463382022-04-21 08:17:14 -0700104 InstrRType (instr) = { \
Chris Wulff032c76b2017-01-18 23:01:41 +0100105 .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 Henderson17463382022-04-21 08:17:14 -0700114typedef struct {
115 uint8_t op;
116 uint32_t imm26;
117} InstrJType;
118
Chris Wulff032c76b2017-01-18 23:01:41 +0100119#define J_TYPE(instr, code) \
Richard Henderson17463382022-04-21 08:17:14 -0700120 InstrJType (instr) = { \
Chris Wulff032c76b2017-01-18 23:01:41 +0100121 .op = extract32((code), 0, 6), \
122 .imm26 = extract32((code), 6, 26), \
123 }
124
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700125typedef void GenFn2i(TCGv, TCGv, target_long);
Richard Henderson7c849042022-04-22 09:25:30 -0700126typedef void GenFn3(TCGv, TCGv, TCGv);
Richard Henderson3099c412022-04-22 09:28:38 -0700127typedef void GenFn4(TCGv, TCGv, TCGv, TCGv);
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700128
Chris Wulff032c76b2017-01-18 23:01:41 +0100129typedef struct DisasContext {
Richard Hendersone9150ea2021-06-19 21:44:48 -0700130 DisasContextBase base;
Chris Wulff032c76b2017-01-18 23:01:41 +0100131 target_ulong pc;
Chris Wulff032c76b2017-01-18 23:01:41 +0100132 int mem_idx;
Richard Henderson945a5bd2022-04-21 08:17:24 -0700133 uint32_t tb_flags;
Richard Henderson7eed8e42022-04-21 08:17:16 -0700134 TCGv sink;
Richard Henderson796945d2022-04-21 08:17:08 -0700135 const ControlRegState *cr_state;
Richard Henderson3a030872022-04-21 08:17:25 -0700136 bool eic_present;
Chris Wulff032c76b2017-01-18 23:01:41 +0100137} DisasContext;
138
Richard Hendersonf1ec0782022-04-21 08:16:50 -0700139static TCGv cpu_R[NUM_GP_REGS];
Richard Henderson17a406e2022-04-21 08:16:47 -0700140static TCGv cpu_pc;
Richard Henderson945a5bd2022-04-21 08:17:24 -0700141#ifndef CONFIG_USER_ONLY
142static TCGv cpu_crs_R[NUM_GP_REGS];
143#endif
Richard Henderson438aabe2021-06-19 21:38:36 -0700144
Chris Wulff032c76b2017-01-18 23:01:41 +0100145typedef struct Nios2Instruction {
146 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
147 uint32_t flags;
148} Nios2Instruction;
149
150static uint8_t get_opcode(uint32_t code)
151{
152 I_TYPE(instr, code);
153 return instr.op;
154}
155
156static uint8_t get_opxcode(uint32_t code)
157{
158 R_TYPE(instr, code);
159 return instr.opx;
160}
161
Richard Henderson718db072022-04-21 08:17:13 -0700162static TCGv load_gpr(DisasContext *dc, unsigned reg)
Chris Wulff032c76b2017-01-18 23:01:41 +0100163{
Richard Henderson718db072022-04-21 08:17:13 -0700164 assert(reg < NUM_GP_REGS);
Richard Henderson945a5bd2022-04-21 08:17:24 -0700165
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 Henderson718db072022-04-21 08:17:13 -0700172 return tcg_constant_tl(0);
Chris Wulff032c76b2017-01-18 23:01:41 +0100173 }
Richard Henderson945a5bd2022-04-21 08:17:24 -0700174 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 Wulff032c76b2017-01-18 23:01:41 +0100182}
183
Richard Henderson7eed8e42022-04-21 08:17:16 -0700184static TCGv dest_gpr(DisasContext *dc, unsigned reg)
185{
186 assert(reg < NUM_GP_REGS);
Richard Henderson945a5bd2022-04-21 08:17:24 -0700187
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 Henderson7eed8e42022-04-21 08:17:16 -0700192 if (unlikely(reg == R_ZERO)) {
193 if (dc->sink == NULL) {
194 dc->sink = tcg_temp_new();
195 }
196 return dc->sink;
197 }
Richard Henderson945a5bd2022-04-21 08:17:24 -0700198 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 Henderson7eed8e42022-04-21 08:17:16 -0700206}
207
Richard Hendersone84f1762022-04-21 08:17:28 -0700208static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
Chris Wulff032c76b2017-01-18 23:01:41 +0100209{
Richard Hendersone84f1762022-04-21 08:17:28 -0700210 /* Note that PC is advanced for all hardware exceptions. */
211 tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
Richard Hendersonad75a512023-09-13 16:37:36 -0700212 gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
Richard Hendersone9150ea2021-06-19 21:44:48 -0700213 dc->base.is_jmp = DISAS_NORETURN;
Chris Wulff032c76b2017-01-18 23:01:41 +0100214}
215
Chris Wulff032c76b2017-01-18 23:01:41 +0100216static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
217{
Richard Hendersone9150ea2021-06-19 21:44:48 -0700218 const TranslationBlock *tb = dc->base.tb;
Chris Wulff032c76b2017-01-18 23:01:41 +0100219
Richard Henderson60824142021-06-20 16:24:00 -0700220 if (translator_use_goto_tb(&dc->base, dest)) {
Chris Wulff032c76b2017-01-18 23:01:41 +0100221 tcg_gen_goto_tb(n);
Richard Henderson17a406e2022-04-21 08:16:47 -0700222 tcg_gen_movi_tl(cpu_pc, dest);
Richard Henderson07ea28b2018-05-30 18:06:23 -0700223 tcg_gen_exit_tb(tb, n);
Chris Wulff032c76b2017-01-18 23:01:41 +0100224 } else {
Richard Henderson17a406e2022-04-21 08:16:47 -0700225 tcg_gen_movi_tl(cpu_pc, dest);
Richard Henderson0e6f22c2022-04-21 08:17:22 -0700226 tcg_gen_lookup_and_goto_ptr();
Chris Wulff032c76b2017-01-18 23:01:41 +0100227 }
Richard Henderson3ad59352022-04-21 08:17:20 -0700228 dc->base.is_jmp = DISAS_NORETURN;
Chris Wulff032c76b2017-01-18 23:01:41 +0100229}
230
Richard Hendersonbd9154a2022-04-21 08:17:19 -0700231static void gen_jumpr(DisasContext *dc, int regno, bool is_call)
232{
Richard Henderson410c6aa2022-04-21 08:17:23 -0700233 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 Henderson410c6aa2022-04-21 08:17:23 -0700239
240 tcg_gen_mov_tl(cpu_pc, dest);
Richard Hendersonbd9154a2022-04-21 08:17:19 -0700241 if (is_call) {
242 tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
243 }
Richard Henderson0e6f22c2022-04-21 08:17:22 -0700244 tcg_gen_lookup_and_goto_ptr();
Richard Henderson410c6aa2022-04-21 08:17:23 -0700245
246 gen_set_label(l);
Richard Hendersonad75a512023-09-13 16:37:36 -0700247 tcg_gen_st_tl(dest, tcg_env, offsetof(CPUNios2State, ctrl[CR_BADADDR]));
Richard Henderson410c6aa2022-04-21 08:17:23 -0700248 t_gen_helper_raise_exception(dc, EXCP_UNALIGND);
249
Richard Hendersonbd9154a2022-04-21 08:17:19 -0700250 dc->base.is_jmp = DISAS_NORETURN;
251}
252
Chris Wulff032c76b2017-01-18 23:01:41 +0100253static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
254{
255 t_gen_helper_raise_exception(dc, flags);
256}
257
Richard Henderson48b7eac2022-04-21 08:16:45 -0700258static bool gen_check_supervisor(DisasContext *dc)
Chris Wulff032c76b2017-01-18 23:01:41 +0100259{
Richard Henderson945a5bd2022-04-21 08:17:24 -0700260 if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) {
Chris Wulff032c76b2017-01-18 23:01:41 +0100261 /* CPU in user mode, privileged instruction called, stop. */
262 t_gen_helper_raise_exception(dc, EXCP_SUPERI);
Richard Henderson48b7eac2022-04-21 08:16:45 -0700263 return false;
Chris Wulff032c76b2017-01-18 23:01:41 +0100264 }
Richard Henderson48b7eac2022-04-21 08:16:45 -0700265 return true;
Chris Wulff032c76b2017-01-18 23:01:41 +0100266}
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 */
272static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
273{
274 /* Nothing to do here */
275}
276
277/*
278 * J-Type instructions
279 */
280static 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 Wulff032c76b2017-01-18 23:01:41 +0100284}
285
286static void call(DisasContext *dc, uint32_t code, uint32_t flags)
287{
Richard Henderson7eed8e42022-04-21 08:17:16 -0700288 tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
Chris Wulff032c76b2017-01-18 23:01:41 +0100289 jmpi(dc, code, flags);
290}
291
292/*
293 * I-Type instructions
294 */
295/* Load instructions */
296static 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 Henderson7eed8e42022-04-21 08:17:16 -0700301 TCGv data = dest_gpr(dc, instr.b);
Chris Wulff032c76b2017-01-18 23:01:41 +0100302
Paolo Bonzini4ae4b602017-03-03 17:28:49 +0100303 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
Richard Hendersona978c372023-05-02 10:38:52 +0100304#ifdef CONFIG_USER_ONLY
305 flags |= MO_UNALN;
306#else
307 flags |= MO_ALIGN;
308#endif
Chris Wulff032c76b2017-01-18 23:01:41 +0100309 tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
Chris Wulff032c76b2017-01-18 23:01:41 +0100310}
311
312/* Store instructions */
313static 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 Bonzini4ae4b602017-03-03 17:28:49 +0100319 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
Richard Hendersona978c372023-05-02 10:38:52 +0100320#ifdef CONFIG_USER_ONLY
321 flags |= MO_UNALN;
322#else
323 flags |= MO_ALIGN;
324#endif
Chris Wulff032c76b2017-01-18 23:01:41 +0100325 tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
Chris Wulff032c76b2017-01-18 23:01:41 +0100326}
327
328/* Branch instructions */
329static void br(DisasContext *dc, uint32_t code, uint32_t flags)
330{
331 I_TYPE(instr, code);
332
Richard Henderson77b42a22021-06-28 14:20:55 -0700333 gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4));
Chris Wulff032c76b2017-01-18 23:01:41 +0100334}
335
336static 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 Henderson7eed8e42022-04-21 08:17:16 -0700341 tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1);
Richard Henderson77b42a22021-06-28 14:20:55 -0700342 gen_goto_tb(dc, 0, dc->base.pc_next);
Chris Wulff032c76b2017-01-18 23:01:41 +0100343 gen_set_label(l1);
Richard Henderson77b42a22021-06-28 14:20:55 -0700344 gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
Chris Wulff032c76b2017-01-18 23:01:41 +0100345}
346
347/* Comparison instructions */
Richard Henderson3d1f63d2022-04-22 09:16:43 -0700348static void do_i_cmpxx(DisasContext *dc, uint32_t insn,
349 TCGCond cond, ImmFromIType *imm)
350{
351 I_TYPE(instr, insn);
Richard Henderson7eed8e42022-04-21 08:17:16 -0700352 tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b),
353 load_gpr(dc, instr.a), imm(&instr));
Chris Wulff032c76b2017-01-18 23:01:41 +0100354}
355
Richard Henderson3d1f63d2022-04-22 09:16:43 -0700356#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
360gen_i_cmpxx(gen_cmpxxsi, imm_signed)
361gen_i_cmpxx(gen_cmpxxui, imm_unsigned)
Chris Wulff032c76b2017-01-18 23:01:41 +0100362
363/* Math/logic instructions */
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700364static 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 Henderson945a5bd2022-04-21 08:17:24 -0700378 if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700379 /* This catches the canonical expansions of movi and movhi. */
Richard Henderson7eed8e42022-04-21 08:17:16 -0700380 tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0);
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700381 } else {
Richard Henderson7eed8e42022-04-21 08:17:16 -0700382 fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val);
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700383 }
Chris Wulff032c76b2017-01-18 23:01:41 +0100384}
385
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700386#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 Wulff032c76b2017-01-18 23:01:41 +0100389
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700390gen_i_math_logic(addi, addi, 1, imm_signed)
391gen_i_math_logic(muli, muli, 0, imm_signed)
Chris Wulff032c76b2017-01-18 23:01:41 +0100392
Richard Hendersoncd419bc2022-04-22 09:19:16 -0700393gen_i_math_logic(andi, andi, 0, imm_unsigned)
394gen_i_math_logic(ori, ori, 1, imm_unsigned)
395gen_i_math_logic(xori, xori, 1, imm_unsigned)
396
397gen_i_math_logic(andhi, andi, 0, imm_shifted)
398gen_i_math_logic(orhi , ori, 1, imm_shifted)
399gen_i_math_logic(xorhi, xori, 1, imm_shifted)
Chris Wulff032c76b2017-01-18 23:01:41 +0100400
Richard Henderson3a030872022-04-21 08:17:25 -0700401/* rB <- prs.rA + sigma(IMM16) */
402static 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 Hendersonad75a512023-09-13 16:37:36 -0700417 gen_helper_rdprs(dest, tcg_env, tcg_constant_i32(instr.a));
Richard Henderson3a030872022-04-21 08:17:25 -0700418 tcg_gen_addi_tl(dest, dest, instr.imm16.s);
419#endif
420}
421
Chris Wulff032c76b2017-01-18 23:01:41 +0100422/* Prototype only, defined below */
423static void handle_r_type_instr(DisasContext *dc, uint32_t code,
424 uint32_t flags);
425
426static 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 Maydell6ab17902023-06-23 18:25:56 +0100438 INSTRUCTION_FLG(gen_ldx, MO_TEUW), /* ldhu */
Chris Wulff032c76b2017-01-18 23:01:41 +0100439 INSTRUCTION(andi), /* andi */
Peter Maydell6ab17902023-06-23 18:25:56 +0100440 INSTRUCTION_FLG(gen_stx, MO_TEUW), /* sth */
Chris Wulff032c76b2017-01-18 23:01:41 +0100441 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */
Peter Maydell6ab17902023-06-23 18:25:56 +0100442 INSTRUCTION_FLG(gen_ldx, MO_TESW), /* ldh */
Chris Wulff032c76b2017-01-18 23:01:41 +0100443 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */
444 INSTRUCTION_ILLEGAL(),
445 INSTRUCTION_ILLEGAL(),
446 INSTRUCTION_NOP(), /* initda */
447 INSTRUCTION(ori), /* ori */
Peter Maydell6ab17902023-06-23 18:25:56 +0100448 INSTRUCTION_FLG(gen_stx, MO_TEUL), /* stw */
Chris Wulff032c76b2017-01-18 23:01:41 +0100449 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */
Peter Maydell6ab17902023-06-23 18:25:56 +0100450 INSTRUCTION_FLG(gen_ldx, MO_TEUL), /* ldw */
Chris Wulff032c76b2017-01-18 23:01:41 +0100451 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 Maydell6ab17902023-06-23 18:25:56 +0100470 INSTRUCTION_FLG(gen_ldx, MO_TEUW), /* ldhuio */
Chris Wulff032c76b2017-01-18 23:01:41 +0100471 INSTRUCTION(andhi), /* andhi */
Peter Maydell6ab17902023-06-23 18:25:56 +0100472 INSTRUCTION_FLG(gen_stx, MO_TEUW), /* sthio */
Chris Wulff032c76b2017-01-18 23:01:41 +0100473 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */
Peter Maydell6ab17902023-06-23 18:25:56 +0100474 INSTRUCTION_FLG(gen_ldx, MO_TESW), /* ldhio */
Chris Wulff032c76b2017-01-18 23:01:41 +0100475 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */
476 INSTRUCTION_ILLEGAL(),
477 INSTRUCTION_UNIMPLEMENTED(), /* custom */
478 INSTRUCTION_NOP(), /* initd */
479 INSTRUCTION(orhi), /* orhi */
Peter Maydell6ab17902023-06-23 18:25:56 +0100480 INSTRUCTION_FLG(gen_stx, MO_TESL), /* stwio */
Chris Wulff032c76b2017-01-18 23:01:41 +0100481 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */
Peter Maydell6ab17902023-06-23 18:25:56 +0100482 INSTRUCTION_FLG(gen_ldx, MO_TEUL), /* ldwio */
Richard Henderson3a030872022-04-21 08:17:25 -0700483 INSTRUCTION(rdprs), /* rdprs */
Chris Wulff032c76b2017-01-18 23:01:41 +0100484 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 */
500static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
501{
Richard Henderson48b7eac2022-04-21 08:16:45 -0700502 if (!gen_check_supervisor(dc)) {
503 return;
504 }
Amir Gonnenb106e7b2022-04-21 08:16:44 -0700505
Amir Gonnen8d855c82022-04-21 08:16:48 -0700506#ifdef CONFIG_USER_ONLY
507 g_assert_not_reached();
508#else
Richard Henderson6bcc59c2022-04-21 08:17:26 -0700509 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
510 TCGv tmp = tcg_temp_new();
Richard Hendersonad75a512023-09-13 16:37:36 -0700511 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 Henderson6bcc59c2022-04-21 08:17:26 -0700513 } else {
Richard Hendersonad75a512023-09-13 16:37:36 -0700514 gen_helper_eret(tcg_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA));
Richard Henderson6bcc59c2022-04-21 08:17:26 -0700515 }
Amir Gonnen8d855c82022-04-21 08:16:48 -0700516 dc->base.is_jmp = DISAS_NORETURN;
517#endif
Chris Wulff032c76b2017-01-18 23:01:41 +0100518}
519
520/* PC <- ra */
521static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
522{
Richard Hendersonbd9154a2022-04-21 08:17:19 -0700523 gen_jumpr(dc, R_RA, false);
Chris Wulff032c76b2017-01-18 23:01:41 +0100524}
525
Richard Henderson48da43b2022-04-21 08:16:49 -0700526/*
527 * status <- bstatus
528 * PC <- ba
529 */
Chris Wulff032c76b2017-01-18 23:01:41 +0100530static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
531{
Richard Henderson48da43b2022-04-21 08:16:49 -0700532 if (!gen_check_supervisor(dc)) {
533 return;
534 }
Chris Wulff032c76b2017-01-18 23:01:41 +0100535
Richard Henderson48da43b2022-04-21 08:16:49 -0700536#ifdef CONFIG_USER_ONLY
537 g_assert_not_reached();
538#else
Richard Hendersonf1ec0782022-04-21 08:16:50 -0700539 TCGv tmp = tcg_temp_new();
Richard Hendersonad75a512023-09-13 16:37:36 -0700540 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 Hendersonf1ec0782022-04-21 08:16:50 -0700542
Richard Henderson48da43b2022-04-21 08:16:49 -0700543 dc->base.is_jmp = DISAS_NORETURN;
544#endif
Chris Wulff032c76b2017-01-18 23:01:41 +0100545}
546
547/* PC <- rA */
548static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
549{
550 R_TYPE(instr, code);
551
Richard Hendersonbd9154a2022-04-21 08:17:19 -0700552 gen_jumpr(dc, instr.a, false);
Chris Wulff032c76b2017-01-18 23:01:41 +0100553}
554
555/* rC <- PC + 4 */
556static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
557{
558 R_TYPE(instr, code);
559
Richard Henderson7eed8e42022-04-21 08:17:16 -0700560 tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next);
Chris Wulff032c76b2017-01-18 23:01:41 +0100561}
562
563/*
564 * ra <- PC + 4
565 * PC <- rA
566 */
567static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
568{
569 R_TYPE(instr, code);
570
Richard Hendersonbd9154a2022-04-21 08:17:19 -0700571 gen_jumpr(dc, instr.a, true);
Chris Wulff032c76b2017-01-18 23:01:41 +0100572}
573
574/* rC <- ctlN */
575static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
576{
Richard Henderson48b7eac2022-04-21 08:16:45 -0700577 if (!gen_check_supervisor(dc)) {
578 return;
579 }
Chris Wulff032c76b2017-01-18 23:01:41 +0100580
Richard Henderson796945d2022-04-21 08:17:08 -0700581#ifdef CONFIG_USER_ONLY
582 g_assert_not_reached();
583#else
584 R_TYPE(instr, code);
Richard Henderson7eed8e42022-04-21 08:17:16 -0700585 TCGv t1, t2, dest = dest_gpr(dc, instr.c);
Richard Henderson0b6e8f52022-02-26 01:06:07 -1000586
Richard Henderson796945d2022-04-21 08:17:08 -0700587 /* Reserved registers read as zero. */
588 if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
Richard Henderson7eed8e42022-04-21 08:17:16 -0700589 tcg_gen_movi_tl(dest, 0);
Richard Henderson796945d2022-04-21 08:17:08 -0700590 return;
591 }
592
Richard Hendersonb8f036a2022-04-21 08:16:53 -0700593 switch (instr.imm5) {
Richard Henderson8d8d73b2022-02-26 01:29:42 -1000594 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 Hendersonf1ec0782022-04-21 08:16:50 -0700603 t1 = tcg_temp_new();
604 t2 = tcg_temp_new();
Richard Hendersonad75a512023-09-13 16:37:36 -0700605 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 Henderson7eed8e42022-04-21 08:17:16 -0700607 tcg_gen_and_tl(dest, t1, t2);
Richard Henderson8d8d73b2022-02-26 01:29:42 -1000608 break;
Chris Wulff032c76b2017-01-18 23:01:41 +0100609 default:
Richard Hendersonad75a512023-09-13 16:37:36 -0700610 tcg_gen_ld_tl(dest, tcg_env,
Richard Hendersonb8f036a2022-04-21 08:16:53 -0700611 offsetof(CPUNios2State, ctrl[instr.imm5]));
Chris Wulff032c76b2017-01-18 23:01:41 +0100612 break;
613 }
Richard Henderson796945d2022-04-21 08:17:08 -0700614#endif
Chris Wulff032c76b2017-01-18 23:01:41 +0100615}
616
617/* ctlN <- rA */
618static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
619{
Richard Henderson48b7eac2022-04-21 08:16:45 -0700620 if (!gen_check_supervisor(dc)) {
621 return;
622 }
Chris Wulff032c76b2017-01-18 23:01:41 +0100623
Richard Henderson48b7eac2022-04-21 08:16:45 -0700624#ifdef CONFIG_USER_ONLY
625 g_assert_not_reached();
626#else
Richard Henderson304c05d2022-02-26 01:27:32 -1000627 R_TYPE(instr, code);
628 TCGv v = load_gpr(dc, instr.a);
Richard Henderson796945d2022-04-21 08:17:08 -0700629 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 Henderson304c05d2022-02-26 01:27:32 -1000637
Richard Hendersonb8f036a2022-04-21 08:16:53 -0700638 switch (instr.imm5) {
Chris Wulff032c76b2017-01-18 23:01:41 +0100639 case CR_PTEADDR:
Richard Hendersonad75a512023-09-13 16:37:36 -0700640 gen_helper_mmu_write_pteaddr(tcg_env, v);
Chris Wulff032c76b2017-01-18 23:01:41 +0100641 break;
Richard Henderson304c05d2022-02-26 01:27:32 -1000642 case CR_TLBACC:
Richard Hendersonad75a512023-09-13 16:37:36 -0700643 gen_helper_mmu_write_tlbacc(tcg_env, v);
Richard Henderson304c05d2022-02-26 01:27:32 -1000644 break;
645 case CR_TLBMISC:
Richard Hendersonad75a512023-09-13 16:37:36 -0700646 gen_helper_mmu_write_tlbmisc(tcg_env, v);
Richard Henderson304c05d2022-02-26 01:27:32 -1000647 break;
Richard Hendersonb72c9d52022-02-26 01:56:15 -1000648 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 Wulff032c76b2017-01-18 23:01:41 +0100653 default:
Richard Henderson796945d2022-04-21 08:17:08 -0700654 if (wr == -1) {
655 /* The register is entirely writable. */
Richard Hendersonad75a512023-09-13 16:37:36 -0700656 tcg_gen_st_tl(v, tcg_env, ofs);
Richard Henderson796945d2022-04-21 08:17:08 -0700657 } 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 Hendersonad75a512023-09-13 16:37:36 -0700668 tcg_gen_ld_tl(o, tcg_env, ofs);
Richard Henderson796945d2022-04-21 08:17:08 -0700669 tcg_gen_andi_tl(o, o, ro);
670 tcg_gen_or_tl(n, n, o);
Richard Henderson796945d2022-04-21 08:17:08 -0700671 }
672
Richard Hendersonad75a512023-09-13 16:37:36 -0700673 tcg_gen_st_tl(n, tcg_env, ofs);
Richard Henderson796945d2022-04-21 08:17:08 -0700674 }
Chris Wulff032c76b2017-01-18 23:01:41 +0100675 break;
676 }
Chris Wulff032c76b2017-01-18 23:01:41 +0100677#endif
678}
679
Richard Henderson3a030872022-04-21 08:17:25 -0700680/* prs.rC <- rA */
681static 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 Hendersonad75a512023-09-13 16:37:36 -0700695 gen_helper_wrprs(tcg_env, tcg_constant_i32(instr.c),
Richard Henderson3a030872022-04-21 08:17:25 -0700696 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 Wulff032c76b2017-01-18 23:01:41 +0100710/* Comparison instructions */
711static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
712{
713 R_TYPE(instr, code);
Richard Henderson7eed8e42022-04-21 08:17:16 -0700714 tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c),
715 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
Chris Wulff032c76b2017-01-18 23:01:41 +0100716}
717
718/* Math/logic instructions */
Richard Henderson7c849042022-04-22 09:25:30 -0700719static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn)
720{
721 R_TYPE(instr, insn);
Richard Henderson7eed8e42022-04-21 08:17:16 -0700722 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5);
Chris Wulff032c76b2017-01-18 23:01:41 +0100723}
724
Richard Henderson7c849042022-04-22 09:25:30 -0700725static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn)
726{
727 R_TYPE(instr, insn);
Richard Henderson7eed8e42022-04-21 08:17:16 -0700728 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b));
Richard Henderson7c849042022-04-22 09:25:30 -0700729}
Chris Wulff032c76b2017-01-18 23:01:41 +0100730
Richard Henderson7c849042022-04-22 09:25:30 -0700731#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
739gen_rr_math_logic(add, add)
740gen_rr_math_logic(sub, sub)
741gen_rr_math_logic(mul, mul)
742
743gen_rr_math_logic(and, and)
744gen_rr_math_logic(or, or)
745gen_rr_math_logic(xor, xor)
746gen_rr_math_logic(nor, nor)
747
748gen_ri_math_logic(srai, sari)
749gen_ri_math_logic(srli, shri)
750gen_ri_math_logic(slli, shli)
751gen_ri_math_logic(roli, rotli)
Chris Wulff032c76b2017-01-18 23:01:41 +0100752
Richard Henderson3099c412022-04-22 09:28:38 -0700753static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn)
754{
755 R_TYPE(instr, insn);
Richard Henderson7eed8e42022-04-21 08:17:16 -0700756 TCGv discard = tcg_temp_new();
Richard Henderson3099c412022-04-22 09:28:38 -0700757
Richard Henderson7eed8e42022-04-21 08:17:16 -0700758 fn(discard, dest_gpr(dc, instr.c),
759 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
Chris Wulff032c76b2017-01-18 23:01:41 +0100760}
761
Richard Henderson3099c412022-04-22 09:28:38 -0700762#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
766gen_rr_mul_high(mulxss, muls2)
767gen_rr_mul_high(mulxuu, mulu2)
768gen_rr_mul_high(mulxsu, mulsu2)
Chris Wulff032c76b2017-01-18 23:01:41 +0100769
Richard Henderson541cb622022-04-22 09:32:26 -0700770static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn)
771{
772 R_TYPE(instr, insn);
Richard Henderson7eed8e42022-04-21 08:17:16 -0700773 TCGv sh = tcg_temp_new();
Richard Henderson541cb622022-04-22 09:32:26 -0700774
Richard Henderson7eed8e42022-04-21 08:17:16 -0700775 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 Wulff032c76b2017-01-18 23:01:41 +0100777}
778
Richard Henderson541cb622022-04-22 09:32:26 -0700779#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
783gen_rr_shift(sra, sar)
784gen_rr_shift(srl, shr)
785gen_rr_shift(sll, shl)
786gen_rr_shift(rol, rotl)
787gen_rr_shift(ror, rotr)
Chris Wulff032c76b2017-01-18 23:01:41 +0100788
789static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
790{
791 R_TYPE(instr, (code));
Richard Hendersonad75a512023-09-13 16:37:36 -0700792 gen_helper_divs(dest_gpr(dc, instr.c), tcg_env,
Richard Henderson345b7a82022-04-21 08:17:12 -0700793 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
Chris Wulff032c76b2017-01-18 23:01:41 +0100794}
795
796static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
797{
798 R_TYPE(instr, (code));
Richard Hendersonad75a512023-09-13 16:37:36 -0700799 gen_helper_divu(dest_gpr(dc, instr.c), tcg_env,
Richard Henderson345b7a82022-04-21 08:17:12 -0700800 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
Chris Wulff032c76b2017-01-18 23:01:41 +0100801}
802
Richard Henderson87d7bfd2021-12-20 18:50:06 -0800803static 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 Hendersonad75a512023-09-13 16:37:36 -0700812 tcg_gen_st_i32(tcg_constant_i32(instr.imm5), tcg_env,
Richard Henderson87d7bfd2021-12-20 18:50:06 -0800813 offsetof(CPUNios2State, error_code));
814#endif
815 t_gen_helper_raise_exception(dc, EXCP_TRAP);
816}
817
Richard Henderson24ca3132022-04-21 08:17:02 -0700818static 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 Maydellcab9f192022-08-22 15:12:28 +0100822 bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U);
Richard Henderson24ca3132022-04-21 08:17:02 -0700823 R_TYPE(instr, code);
Peter Maydellcab9f192022-08-22 15:12:28 +0100824 if (semihosting_enabled(is_user) && instr.imm5 == 1) {
Richard Henderson24ca3132022-04-21 08:17:02 -0700825 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 Wulff032c76b2017-01-18 23:01:41 +0100833static 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 Henderson3a030872022-04-21 08:17:25 -0700854 INSTRUCTION(wrprs), /* wrprs */
Chris Wulff032c76b2017-01-18 23:01:41 +0100855 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 Henderson87d7bfd2021-12-20 18:50:06 -0800879 INSTRUCTION(trap), /* trap */
Chris Wulff032c76b2017-01-18 23:01:41 +0100880 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 Henderson24ca3132022-04-21 08:17:02 -0700886 INSTRUCTION(gen_break), /* break */
Chris Wulff032c76b2017-01-18 23:01:41 +0100887 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
900static 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
915illegal_op:
916 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
917}
918
Richard Hendersonb8f036a2022-04-21 08:16:53 -0700919static const char * const gr_regnames[NUM_GP_REGS] = {
Chris Wulff032c76b2017-01-18 23:01:41 +0100920 "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 Hendersonb8f036a2022-04-21 08:16:53 -0700928};
929
Richard Henderson5dfb9102022-04-21 08:16:54 -0700930#ifndef CONFIG_USER_ONLY
Richard Hendersonb8f036a2022-04-21 08:16:53 -0700931static const char * const cr_regnames[NUM_CR_REGS] = {
Chris Wulff032c76b2017-01-18 23:01:41 +0100932 "status", "estatus", "bstatus", "ienable",
Richard Henderson5dfb9102022-04-21 08:16:54 -0700933 "ipending", "cpuid", "res6", "exception",
Chris Wulff032c76b2017-01-18 23:01:41 +0100934 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
935 "badaddr", "config", "mpubase", "mpuacc",
Richard Henderson5dfb9102022-04-21 08:16:54 -0700936 "res16", "res17", "res18", "res19",
937 "res20", "res21", "res22", "res23",
938 "res24", "res25", "res26", "res27",
939 "res28", "res29", "res30", "res31",
Chris Wulff032c76b2017-01-18 23:01:41 +0100940};
Richard Henderson5dfb9102022-04-21 08:16:54 -0700941#endif
Chris Wulff032c76b2017-01-18 23:01:41 +0100942
Chris Wulff032c76b2017-01-18 23:01:41 +0100943/* generate intermediate code for basic block 'tb'. */
Richard Hendersond67cbd92021-06-19 22:12:17 -0700944static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
Chris Wulff032c76b2017-01-18 23:01:41 +0100945{
Richard Hendersond67cbd92021-06-19 22:12:17 -0700946 DisasContext *dc = container_of(dcbase, DisasContext, base);
Richard Hendersonb77af262023-09-13 17:22:49 -0700947 CPUNios2State *env = cpu_env(cs);
Richard Henderson796945d2022-04-21 08:17:08 -0700948 Nios2CPU *cpu = env_archcpu(env);
Richard Hendersond67cbd92021-06-19 22:12:17 -0700949 int page_insns;
Richard Hendersone9150ea2021-06-19 21:44:48 -0700950
Chris Wulff032c76b2017-01-18 23:01:41 +0100951 dc->mem_idx = cpu_mmu_index(env, false);
Richard Henderson796945d2022-04-21 08:17:08 -0700952 dc->cr_state = cpu->cr_state;
Richard Henderson945a5bd2022-04-21 08:17:24 -0700953 dc->tb_flags = dc->base.tb->flags;
Richard Henderson3a030872022-04-21 08:17:25 -0700954 dc->eic_present = cpu->eic_present;
Chris Wulff032c76b2017-01-18 23:01:41 +0100955
Richard Hendersond67cbd92021-06-19 22:12:17 -0700956 /* 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 Wulff032c76b2017-01-18 23:01:41 +0100960
Richard Hendersond67cbd92021-06-19 22:12:17 -0700961static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
962{
963}
Chris Wulff032c76b2017-01-18 23:01:41 +0100964
Richard Hendersond67cbd92021-06-19 22:12:17 -0700965static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
966{
967 tcg_gen_insn_start(dcbase->pc_next);
968}
Chris Wulff032c76b2017-01-18 23:01:41 +0100969
Richard Hendersond67cbd92021-06-19 22:12:17 -0700970static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
971{
972 DisasContext *dc = container_of(dcbase, DisasContext, base);
Richard Hendersonb77af262023-09-13 17:22:49 -0700973 CPUNios2State *env = cpu_env(cs);
Richard Henderson1ff375d2021-06-28 14:04:24 -0700974 const Nios2Instruction *instr;
975 uint32_t code, pc;
976 uint8_t op;
Chris Wulff032c76b2017-01-18 23:01:41 +0100977
Richard Henderson1ff375d2021-06-28 14:04:24 -0700978 pc = dc->base.pc_next;
979 dc->pc = pc;
980 dc->base.pc_next = pc + 4;
Richard Hendersond67cbd92021-06-19 22:12:17 -0700981
982 /* Decode an instruction */
Richard Henderson1ff375d2021-06-28 14:04:24 -0700983 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 Henderson7eed8e42022-04-21 08:17:16 -0700991 dc->sink = NULL;
992
Richard Henderson1ff375d2021-06-28 14:04:24 -0700993 instr = &i_type_instructions[op];
994 instr->handler(dc, code, instr->flags);
Richard Hendersond67cbd92021-06-19 22:12:17 -0700995}
996
997static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
998{
999 DisasContext *dc = container_of(dcbase, DisasContext, base);
Chris Wulff032c76b2017-01-18 23:01:41 +01001000
Chris Wulff032c76b2017-01-18 23:01:41 +01001001 /* Indicate where the next block should start */
Richard Hendersone9150ea2021-06-19 21:44:48 -07001002 switch (dc->base.is_jmp) {
Richard Hendersond67cbd92021-06-19 22:12:17 -07001003 case DISAS_TOO_MANY:
Richard Henderson5b843282022-04-21 08:17:21 -07001004 gen_goto_tb(dc, 0, dc->base.pc_next);
1005 break;
1006
Wentong Wuc7694532020-07-13 14:36:10 +01001007 case DISAS_UPDATE:
Richard Henderson5b843282022-04-21 08:17:21 -07001008 /* Save the current PC, and return to the main loop. */
Richard Henderson17a406e2022-04-21 08:16:47 -07001009 tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
Richard Henderson07ea28b2018-05-30 18:06:23 -07001010 tcg_gen_exit_tb(NULL, 0);
Chris Wulff032c76b2017-01-18 23:01:41 +01001011 break;
1012
Wentong Wu42928f22020-07-13 14:36:10 +01001013 case DISAS_NORETURN:
Chris Wulff032c76b2017-01-18 23:01:41 +01001014 /* nothing more to generate */
1015 break;
Richard Hendersond67cbd92021-06-19 22:12:17 -07001016
1017 default:
1018 g_assert_not_reached();
Chris Wulff032c76b2017-01-18 23:01:41 +01001019 }
Richard Hendersond67cbd92021-06-19 22:12:17 -07001020}
Chris Wulff032c76b2017-01-18 23:01:41 +01001021
Richard Henderson8eb806a2022-04-17 11:29:52 -07001022static void nios2_tr_disas_log(const DisasContextBase *dcbase,
1023 CPUState *cpu, FILE *logfile)
Richard Hendersond67cbd92021-06-19 22:12:17 -07001024{
Richard Henderson8eb806a2022-04-17 11:29:52 -07001025 fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
1026 target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
Richard Hendersond67cbd92021-06-19 22:12:17 -07001027}
Chris Wulff032c76b2017-01-18 23:01:41 +01001028
Richard Hendersond67cbd92021-06-19 22:12:17 -07001029static 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 Hendersond67cbd92021-06-19 22:12:17 -07001033 .translate_insn = nios2_tr_translate_insn,
1034 .tb_stop = nios2_tr_tb_stop,
1035 .disas_log = nios2_tr_disas_log,
1036};
Chris Wulff032c76b2017-01-18 23:01:41 +01001037
Richard Henderson597f9b22023-01-28 15:19:22 -10001038void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
Richard Henderson306c8722022-08-11 13:48:03 -07001039 target_ulong pc, void *host_pc)
Richard Hendersond67cbd92021-06-19 22:12:17 -07001040{
1041 DisasContext dc;
Richard Henderson306c8722022-08-11 13:48:03 -07001042 translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base);
Chris Wulff032c76b2017-01-18 23:01:41 +01001043}
1044
Markus Armbruster90c84c52019-04-17 21:18:02 +02001045void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
Chris Wulff032c76b2017-01-18 23:01:41 +01001046{
1047 Nios2CPU *cpu = NIOS2_CPU(cs);
1048 CPUNios2State *env = &cpu->env;
1049 int i;
1050
Richard Henderson17a406e2022-04-21 08:16:47 -07001051 qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
Chris Wulff032c76b2017-01-18 23:01:41 +01001052
Richard Hendersonb8f036a2022-04-21 08:16:53 -07001053 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 Henderson5dfb9102022-04-21 08:16:54 -07001059
1060#if !defined(CONFIG_USER_ONLY)
Richard Henderson796945d2022-04-21 08:17:08 -07001061 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 Wulff032c76b2017-01-18 23:01:41 +01001069 }
1070 }
Richard Henderson796945d2022-04-21 08:17:08 -07001071 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 Wulff032c76b2017-01-18 23:01:41 +01001080#endif
Markus Armbruster90c84c52019-04-17 21:18:02 +02001081 qemu_fprintf(f, "\n\n");
Chris Wulff032c76b2017-01-18 23:01:41 +01001082}
1083
1084void nios2_tcg_init(void)
1085{
Richard Henderson945a5bd2022-04-21 08:17:24 -07001086#ifndef CONFIG_USER_ONLY
Richard Hendersonad75a512023-09-13 16:37:36 -07001087 TCGv_ptr crs = tcg_global_mem_new_ptr(tcg_env,
Richard Henderson945a5bd2022-04-21 08:17:24 -07001088 offsetof(CPUNios2State, regs), "crs");
Chris Wulff032c76b2017-01-18 23:01:41 +01001089
Richard Henderson945a5bd2022-04-21 08:17:24 -07001090 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 Hendersonad75a512023-09-13 16:37:36 -07001100 cpu_R[i] = tcg_global_mem_new(tcg_env, offsetof_regs0(i),
Richard Hendersonb8f036a2022-04-21 08:16:53 -07001101 gr_regnames[i]);
Chris Wulff032c76b2017-01-18 23:01:41 +01001102 }
Richard Henderson945a5bd2022-04-21 08:17:24 -07001103
1104#undef offsetof_regs0
1105
Richard Hendersonad75a512023-09-13 16:37:36 -07001106 cpu_pc = tcg_global_mem_new(tcg_env,
Richard Henderson17a406e2022-04-21 08:16:47 -07001107 offsetof(CPUNios2State, pc), "pc");
Chris Wulff032c76b2017-01-18 23:01:41 +01001108}