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