qapi: allow unions to contain further unions
[qemu/armbru.git] / target / nios2 / translate.c
blob6610e22236ea64335263d4b37283fc0a6e69420c
1 /*
2 * Altera Nios II emulation for qemu: main translation routines.
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.)
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.
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.
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>
24 #include "qemu/osdep.h"
25 #include "cpu.h"
26 #include "tcg/tcg-op.h"
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"
33 #include "exec/translator.h"
34 #include "qemu/qemu-print.h"
35 #include "exec/gen-icount.h"
36 #include "semihosting/semihost.h"
38 /* is_jmp field values */
39 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
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)
51 /* Special R-Type instruction opcode */
52 #define INSN_R_TYPE 0x3A
54 /* I-Type instruction parsing */
55 typedef 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;
65 #define I_TYPE(instr, code) \
66 InstrIType (instr) = { \
67 .op = extract32((code), 0, 6), \
68 .imm16.u = extract32((code), 6, 16), \
69 .b = extract32((code), 22, 5), \
70 .a = extract32((code), 27, 5), \
73 typedef target_ulong ImmFromIType(const InstrIType *);
75 static target_ulong imm_unsigned(const InstrIType *i)
77 return i->imm16.u;
80 static target_ulong imm_signed(const InstrIType *i)
82 return i->imm16.s;
85 static target_ulong imm_shifted(const InstrIType *i)
87 return i->imm16.u << 16;
90 /* R-Type instruction parsing */
91 typedef 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;
100 #define R_TYPE(instr, code) \
101 InstrRType (instr) = { \
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), \
110 /* J-Type instruction parsing */
111 typedef struct {
112 uint8_t op;
113 uint32_t imm26;
114 } InstrJType;
116 #define J_TYPE(instr, code) \
117 InstrJType (instr) = { \
118 .op = extract32((code), 0, 6), \
119 .imm26 = extract32((code), 6, 26), \
122 typedef void GenFn2i(TCGv, TCGv, target_long);
123 typedef void GenFn3(TCGv, TCGv, TCGv);
124 typedef void GenFn4(TCGv, TCGv, TCGv, TCGv);
126 typedef struct DisasContext {
127 DisasContextBase base;
128 target_ulong pc;
129 int mem_idx;
130 uint32_t tb_flags;
131 TCGv sink;
132 const ControlRegState *cr_state;
133 bool eic_present;
134 } DisasContext;
136 static TCGv cpu_R[NUM_GP_REGS];
137 static TCGv cpu_pc;
138 #ifndef CONFIG_USER_ONLY
139 static TCGv cpu_crs_R[NUM_GP_REGS];
140 #endif
142 typedef struct Nios2Instruction {
143 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
144 uint32_t flags;
145 } Nios2Instruction;
147 static uint8_t get_opcode(uint32_t code)
149 I_TYPE(instr, code);
150 return instr.op;
153 static uint8_t get_opxcode(uint32_t code)
155 R_TYPE(instr, code);
156 return instr.opx;
159 static TCGv load_gpr(DisasContext *dc, unsigned reg)
161 assert(reg < NUM_GP_REGS);
164 * With shadow register sets, register r0 does not necessarily contain 0,
165 * but it is overwhelmingly likely that it does -- software is supposed
166 * to have set r0 to 0 in every shadow register set before use.
168 if (unlikely(reg == R_ZERO) && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
169 return tcg_constant_tl(0);
171 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
172 return cpu_R[reg];
174 #ifdef CONFIG_USER_ONLY
175 g_assert_not_reached();
176 #else
177 return cpu_crs_R[reg];
178 #endif
181 static TCGv dest_gpr(DisasContext *dc, unsigned reg)
183 assert(reg < NUM_GP_REGS);
186 * The spec for shadow register sets isn't clear, but we assume that
187 * writes to r0 are discarded regardless of CRS.
189 if (unlikely(reg == R_ZERO)) {
190 if (dc->sink == NULL) {
191 dc->sink = tcg_temp_new();
193 return dc->sink;
195 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
196 return cpu_R[reg];
198 #ifdef CONFIG_USER_ONLY
199 g_assert_not_reached();
200 #else
201 return cpu_crs_R[reg];
202 #endif
205 static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
207 /* Note that PC is advanced for all hardware exceptions. */
208 tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
209 gen_helper_raise_exception(cpu_env, tcg_constant_i32(index));
210 dc->base.is_jmp = DISAS_NORETURN;
213 static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
215 const TranslationBlock *tb = dc->base.tb;
217 if (translator_use_goto_tb(&dc->base, dest)) {
218 tcg_gen_goto_tb(n);
219 tcg_gen_movi_tl(cpu_pc, dest);
220 tcg_gen_exit_tb(tb, n);
221 } else {
222 tcg_gen_movi_tl(cpu_pc, dest);
223 tcg_gen_lookup_and_goto_ptr();
225 dc->base.is_jmp = DISAS_NORETURN;
228 static void gen_jumpr(DisasContext *dc, int regno, bool is_call)
230 TCGLabel *l = gen_new_label();
231 TCGv test = tcg_temp_new();
232 TCGv dest = load_gpr(dc, regno);
234 tcg_gen_andi_tl(test, dest, 3);
235 tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l);
237 tcg_gen_mov_tl(cpu_pc, dest);
238 if (is_call) {
239 tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
241 tcg_gen_lookup_and_goto_ptr();
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);
247 dc->base.is_jmp = DISAS_NORETURN;
250 static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
252 t_gen_helper_raise_exception(dc, flags);
255 static bool gen_check_supervisor(DisasContext *dc)
257 if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) {
258 /* CPU in user mode, privileged instruction called, stop. */
259 t_gen_helper_raise_exception(dc, EXCP_SUPERI);
260 return false;
262 return true;
266 * Used as a placeholder for all instructions which do not have
267 * an effect on the simulator (e.g. flush, sync)
269 static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
271 /* Nothing to do here */
275 * J-Type instructions
277 static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
279 J_TYPE(instr, code);
280 gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
283 static void call(DisasContext *dc, uint32_t code, uint32_t flags)
285 tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
286 jmpi(dc, code, flags);
290 * I-Type instructions
292 /* Load instructions */
293 static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
295 I_TYPE(instr, code);
297 TCGv addr = tcg_temp_new();
298 TCGv data = dest_gpr(dc, instr.b);
300 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
301 tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
304 /* Store instructions */
305 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
307 I_TYPE(instr, code);
308 TCGv val = load_gpr(dc, instr.b);
310 TCGv addr = tcg_temp_new();
311 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
312 tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
315 /* Branch instructions */
316 static void br(DisasContext *dc, uint32_t code, uint32_t flags)
318 I_TYPE(instr, code);
320 gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4));
323 static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
325 I_TYPE(instr, code);
327 TCGLabel *l1 = gen_new_label();
328 tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1);
329 gen_goto_tb(dc, 0, dc->base.pc_next);
330 gen_set_label(l1);
331 gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
334 /* Comparison instructions */
335 static void do_i_cmpxx(DisasContext *dc, uint32_t insn,
336 TCGCond cond, ImmFromIType *imm)
338 I_TYPE(instr, insn);
339 tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b),
340 load_gpr(dc, instr.a), imm(&instr));
343 #define gen_i_cmpxx(fname, imm) \
344 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
345 { do_i_cmpxx(dc, code, flags, imm); }
347 gen_i_cmpxx(gen_cmpxxsi, imm_signed)
348 gen_i_cmpxx(gen_cmpxxui, imm_unsigned)
350 /* Math/logic instructions */
351 static void do_i_math_logic(DisasContext *dc, uint32_t insn,
352 GenFn2i *fn, ImmFromIType *imm,
353 bool x_op_0_eq_x)
355 I_TYPE(instr, insn);
356 target_ulong val;
358 if (unlikely(instr.b == R_ZERO)) {
359 /* Store to R_ZERO is ignored -- this catches the canonical NOP. */
360 return;
363 val = imm(&instr);
365 if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
366 /* This catches the canonical expansions of movi and movhi. */
367 tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0);
368 } else {
369 fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val);
373 #define gen_i_math_logic(fname, insn, x_op_0, imm) \
374 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
375 { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); }
377 gen_i_math_logic(addi, addi, 1, imm_signed)
378 gen_i_math_logic(muli, muli, 0, imm_signed)
380 gen_i_math_logic(andi, andi, 0, imm_unsigned)
381 gen_i_math_logic(ori, ori, 1, imm_unsigned)
382 gen_i_math_logic(xori, xori, 1, imm_unsigned)
384 gen_i_math_logic(andhi, andi, 0, imm_shifted)
385 gen_i_math_logic(orhi , ori, 1, imm_shifted)
386 gen_i_math_logic(xorhi, xori, 1, imm_shifted)
388 /* rB <- prs.rA + sigma(IMM16) */
389 static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags)
391 if (!dc->eic_present) {
392 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
393 return;
395 if (!gen_check_supervisor(dc)) {
396 return;
399 #ifdef CONFIG_USER_ONLY
400 g_assert_not_reached();
401 #else
402 I_TYPE(instr, code);
403 TCGv dest = dest_gpr(dc, instr.b);
404 gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a));
405 tcg_gen_addi_tl(dest, dest, instr.imm16.s);
406 #endif
409 /* Prototype only, defined below */
410 static void handle_r_type_instr(DisasContext *dc, uint32_t code,
411 uint32_t flags);
413 static const Nios2Instruction i_type_instructions[] = {
414 INSTRUCTION(call), /* call */
415 INSTRUCTION(jmpi), /* jmpi */
416 INSTRUCTION_ILLEGAL(),
417 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */
418 INSTRUCTION(addi), /* addi */
419 INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */
420 INSTRUCTION(br), /* br */
421 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */
422 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */
423 INSTRUCTION_ILLEGAL(),
424 INSTRUCTION_ILLEGAL(),
425 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhu */
426 INSTRUCTION(andi), /* andi */
427 INSTRUCTION_FLG(gen_stx, MO_UW), /* sth */
428 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */
429 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldh */
430 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */
431 INSTRUCTION_ILLEGAL(),
432 INSTRUCTION_ILLEGAL(),
433 INSTRUCTION_NOP(), /* initda */
434 INSTRUCTION(ori), /* ori */
435 INSTRUCTION_FLG(gen_stx, MO_UL), /* stw */
436 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */
437 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldw */
438 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */
439 INSTRUCTION_ILLEGAL(),
440 INSTRUCTION_ILLEGAL(),
441 INSTRUCTION_NOP(), /* flushda */
442 INSTRUCTION(xori), /* xori */
443 INSTRUCTION_ILLEGAL(),
444 INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */
445 INSTRUCTION_ILLEGAL(),
446 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */
447 INSTRUCTION_ILLEGAL(),
448 INSTRUCTION_ILLEGAL(),
449 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */
450 INSTRUCTION(muli), /* muli */
451 INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */
452 INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */
453 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */
454 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */
455 INSTRUCTION_ILLEGAL(),
456 INSTRUCTION_ILLEGAL(),
457 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhuio */
458 INSTRUCTION(andhi), /* andhi */
459 INSTRUCTION_FLG(gen_stx, MO_UW), /* sthio */
460 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */
461 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldhio */
462 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */
463 INSTRUCTION_ILLEGAL(),
464 INSTRUCTION_UNIMPLEMENTED(), /* custom */
465 INSTRUCTION_NOP(), /* initd */
466 INSTRUCTION(orhi), /* orhi */
467 INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */
468 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */
469 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */
470 INSTRUCTION(rdprs), /* rdprs */
471 INSTRUCTION_ILLEGAL(),
472 INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */
473 INSTRUCTION_NOP(), /* flushd */
474 INSTRUCTION(xorhi), /* xorhi */
475 INSTRUCTION_ILLEGAL(),
476 INSTRUCTION_ILLEGAL(),
477 INSTRUCTION_ILLEGAL(),
481 * R-Type instructions
484 * status <- estatus
485 * PC <- ea
487 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
489 if (!gen_check_supervisor(dc)) {
490 return;
493 #ifdef CONFIG_USER_ONLY
494 g_assert_not_reached();
495 #else
496 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
497 TCGv tmp = tcg_temp_new();
498 tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS]));
499 gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_EA));
500 } else {
501 gen_helper_eret(cpu_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA));
503 dc->base.is_jmp = DISAS_NORETURN;
504 #endif
507 /* PC <- ra */
508 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
510 gen_jumpr(dc, R_RA, false);
514 * status <- bstatus
515 * PC <- ba
517 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
519 if (!gen_check_supervisor(dc)) {
520 return;
523 #ifdef CONFIG_USER_ONLY
524 g_assert_not_reached();
525 #else
526 TCGv tmp = tcg_temp_new();
527 tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS]));
528 gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_BA));
530 dc->base.is_jmp = DISAS_NORETURN;
531 #endif
534 /* PC <- rA */
535 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
537 R_TYPE(instr, code);
539 gen_jumpr(dc, instr.a, false);
542 /* rC <- PC + 4 */
543 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
545 R_TYPE(instr, code);
547 tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next);
551 * ra <- PC + 4
552 * PC <- rA
554 static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
556 R_TYPE(instr, code);
558 gen_jumpr(dc, instr.a, true);
561 /* rC <- ctlN */
562 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
564 if (!gen_check_supervisor(dc)) {
565 return;
568 #ifdef CONFIG_USER_ONLY
569 g_assert_not_reached();
570 #else
571 R_TYPE(instr, code);
572 TCGv t1, t2, dest = dest_gpr(dc, instr.c);
574 /* Reserved registers read as zero. */
575 if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
576 tcg_gen_movi_tl(dest, 0);
577 return;
580 switch (instr.imm5) {
581 case CR_IPENDING:
583 * The value of the ipending register is synthetic.
584 * In hw, this is the AND of a set of hardware irq lines
585 * with the ienable register. In qemu, we re-use the space
586 * of CR_IPENDING to store the set of irq lines, and so we
587 * must perform the AND here, and anywhere else we need the
588 * guest value of ipending.
590 t1 = tcg_temp_new();
591 t2 = tcg_temp_new();
592 tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ctrl[CR_IPENDING]));
593 tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ctrl[CR_IENABLE]));
594 tcg_gen_and_tl(dest, t1, t2);
595 break;
596 default:
597 tcg_gen_ld_tl(dest, cpu_env,
598 offsetof(CPUNios2State, ctrl[instr.imm5]));
599 break;
601 #endif
604 /* ctlN <- rA */
605 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
607 if (!gen_check_supervisor(dc)) {
608 return;
611 #ifdef CONFIG_USER_ONLY
612 g_assert_not_reached();
613 #else
614 R_TYPE(instr, code);
615 TCGv v = load_gpr(dc, instr.a);
616 uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]);
617 uint32_t wr = dc->cr_state[instr.imm5].writable;
618 uint32_t ro = dc->cr_state[instr.imm5].readonly;
620 /* Skip reserved or readonly registers. */
621 if (wr == 0) {
622 return;
625 switch (instr.imm5) {
626 case CR_PTEADDR:
627 gen_helper_mmu_write_pteaddr(cpu_env, v);
628 break;
629 case CR_TLBACC:
630 gen_helper_mmu_write_tlbacc(cpu_env, v);
631 break;
632 case CR_TLBMISC:
633 gen_helper_mmu_write_tlbmisc(cpu_env, v);
634 break;
635 case CR_STATUS:
636 case CR_IENABLE:
637 /* If interrupts were enabled using WRCTL, trigger them. */
638 dc->base.is_jmp = DISAS_UPDATE;
639 /* fall through */
640 default:
641 if (wr == -1) {
642 /* The register is entirely writable. */
643 tcg_gen_st_tl(v, cpu_env, ofs);
644 } else {
646 * The register is partially read-only or reserved:
647 * merge the value.
649 TCGv n = tcg_temp_new();
651 tcg_gen_andi_tl(n, v, wr);
653 if (ro != 0) {
654 TCGv o = tcg_temp_new();
655 tcg_gen_ld_tl(o, cpu_env, ofs);
656 tcg_gen_andi_tl(o, o, ro);
657 tcg_gen_or_tl(n, n, o);
660 tcg_gen_st_tl(n, cpu_env, ofs);
662 break;
664 #endif
667 /* prs.rC <- rA */
668 static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags)
670 if (!dc->eic_present) {
671 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
672 return;
674 if (!gen_check_supervisor(dc)) {
675 return;
678 #ifdef CONFIG_USER_ONLY
679 g_assert_not_reached();
680 #else
681 R_TYPE(instr, code);
682 gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c),
683 load_gpr(dc, instr.a));
685 * The expected write to PRS[r0] is 0, from CRS[r0].
686 * If not, and CRS == PRS (which we cannot tell from here),
687 * we may now have a non-zero value in our current r0.
688 * By ending the TB, we re-evaluate tb_flags and find out.
690 if (instr.c == 0
691 && (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) {
692 dc->base.is_jmp = DISAS_UPDATE;
694 #endif
697 /* Comparison instructions */
698 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
700 R_TYPE(instr, code);
701 tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c),
702 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
705 /* Math/logic instructions */
706 static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn)
708 R_TYPE(instr, insn);
709 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5);
712 static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn)
714 R_TYPE(instr, insn);
715 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b));
718 #define gen_ri_math_logic(fname, insn) \
719 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
720 { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); }
722 #define gen_rr_math_logic(fname, insn) \
723 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
724 { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); }
726 gen_rr_math_logic(add, add)
727 gen_rr_math_logic(sub, sub)
728 gen_rr_math_logic(mul, mul)
730 gen_rr_math_logic(and, and)
731 gen_rr_math_logic(or, or)
732 gen_rr_math_logic(xor, xor)
733 gen_rr_math_logic(nor, nor)
735 gen_ri_math_logic(srai, sari)
736 gen_ri_math_logic(srli, shri)
737 gen_ri_math_logic(slli, shli)
738 gen_ri_math_logic(roli, rotli)
740 static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn)
742 R_TYPE(instr, insn);
743 TCGv discard = tcg_temp_new();
745 fn(discard, dest_gpr(dc, instr.c),
746 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
749 #define gen_rr_mul_high(fname, insn) \
750 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
751 { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); }
753 gen_rr_mul_high(mulxss, muls2)
754 gen_rr_mul_high(mulxuu, mulu2)
755 gen_rr_mul_high(mulxsu, mulsu2)
757 static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn)
759 R_TYPE(instr, insn);
760 TCGv sh = tcg_temp_new();
762 tcg_gen_andi_tl(sh, load_gpr(dc, instr.b), 31);
763 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), sh);
766 #define gen_rr_shift(fname, insn) \
767 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
768 { do_rr_shift(dc, code, tcg_gen_##insn##_tl); }
770 gen_rr_shift(sra, sar)
771 gen_rr_shift(srl, shr)
772 gen_rr_shift(sll, shl)
773 gen_rr_shift(rol, rotl)
774 gen_rr_shift(ror, rotr)
776 static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
778 R_TYPE(instr, (code));
779 gen_helper_divs(dest_gpr(dc, instr.c), cpu_env,
780 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
783 static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
785 R_TYPE(instr, (code));
786 gen_helper_divu(dest_gpr(dc, instr.c), cpu_env,
787 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
790 static void trap(DisasContext *dc, uint32_t code, uint32_t flags)
792 #ifdef CONFIG_USER_ONLY
794 * The imm5 field is not stored anywhere on real hw; the kernel
795 * has to load the insn and extract the field. But we can make
796 * things easier for cpu_loop if we pop this into env->error_code.
798 R_TYPE(instr, code);
799 tcg_gen_st_i32(tcg_constant_i32(instr.imm5), cpu_env,
800 offsetof(CPUNios2State, error_code));
801 #endif
802 t_gen_helper_raise_exception(dc, EXCP_TRAP);
805 static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags)
807 #ifndef CONFIG_USER_ONLY
808 /* The semihosting instruction is "break 1". */
809 bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U);
810 R_TYPE(instr, code);
811 if (semihosting_enabled(is_user) && instr.imm5 == 1) {
812 t_gen_helper_raise_exception(dc, EXCP_SEMIHOST);
813 return;
815 #endif
817 t_gen_helper_raise_exception(dc, EXCP_BREAK);
820 static const Nios2Instruction r_type_instructions[] = {
821 INSTRUCTION_ILLEGAL(),
822 INSTRUCTION(eret), /* eret */
823 INSTRUCTION(roli), /* roli */
824 INSTRUCTION(rol), /* rol */
825 INSTRUCTION_NOP(), /* flushp */
826 INSTRUCTION(ret), /* ret */
827 INSTRUCTION(nor), /* nor */
828 INSTRUCTION(mulxuu), /* mulxuu */
829 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */
830 INSTRUCTION(bret), /* bret */
831 INSTRUCTION_ILLEGAL(),
832 INSTRUCTION(ror), /* ror */
833 INSTRUCTION_NOP(), /* flushi */
834 INSTRUCTION(jmp), /* jmp */
835 INSTRUCTION(and), /* and */
836 INSTRUCTION_ILLEGAL(),
837 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */
838 INSTRUCTION_ILLEGAL(),
839 INSTRUCTION(slli), /* slli */
840 INSTRUCTION(sll), /* sll */
841 INSTRUCTION(wrprs), /* wrprs */
842 INSTRUCTION_ILLEGAL(),
843 INSTRUCTION(or), /* or */
844 INSTRUCTION(mulxsu), /* mulxsu */
845 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */
846 INSTRUCTION_ILLEGAL(),
847 INSTRUCTION(srli), /* srli */
848 INSTRUCTION(srl), /* srl */
849 INSTRUCTION(nextpc), /* nextpc */
850 INSTRUCTION(callr), /* callr */
851 INSTRUCTION(xor), /* xor */
852 INSTRUCTION(mulxss), /* mulxss */
853 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */
854 INSTRUCTION_ILLEGAL(),
855 INSTRUCTION_ILLEGAL(),
856 INSTRUCTION_ILLEGAL(),
857 INSTRUCTION(divu), /* divu */
858 INSTRUCTION(divs), /* div */
859 INSTRUCTION(rdctl), /* rdctl */
860 INSTRUCTION(mul), /* mul */
861 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */
862 INSTRUCTION_NOP(), /* initi */
863 INSTRUCTION_ILLEGAL(),
864 INSTRUCTION_ILLEGAL(),
865 INSTRUCTION_ILLEGAL(),
866 INSTRUCTION(trap), /* trap */
867 INSTRUCTION(wrctl), /* wrctl */
868 INSTRUCTION_ILLEGAL(),
869 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */
870 INSTRUCTION(add), /* add */
871 INSTRUCTION_ILLEGAL(),
872 INSTRUCTION_ILLEGAL(),
873 INSTRUCTION(gen_break), /* break */
874 INSTRUCTION_ILLEGAL(),
875 INSTRUCTION(nop), /* nop */
876 INSTRUCTION_ILLEGAL(),
877 INSTRUCTION_ILLEGAL(),
878 INSTRUCTION(sub), /* sub */
879 INSTRUCTION(srai), /* srai */
880 INSTRUCTION(sra), /* sra */
881 INSTRUCTION_ILLEGAL(),
882 INSTRUCTION_ILLEGAL(),
883 INSTRUCTION_ILLEGAL(),
884 INSTRUCTION_ILLEGAL(),
887 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
889 uint8_t opx;
890 const Nios2Instruction *instr;
892 opx = get_opxcode(code);
893 if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
894 goto illegal_op;
897 instr = &r_type_instructions[opx];
898 instr->handler(dc, code, instr->flags);
900 return;
902 illegal_op:
903 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
906 static const char * const gr_regnames[NUM_GP_REGS] = {
907 "zero", "at", "r2", "r3",
908 "r4", "r5", "r6", "r7",
909 "r8", "r9", "r10", "r11",
910 "r12", "r13", "r14", "r15",
911 "r16", "r17", "r18", "r19",
912 "r20", "r21", "r22", "r23",
913 "et", "bt", "gp", "sp",
914 "fp", "ea", "ba", "ra",
917 #ifndef CONFIG_USER_ONLY
918 static const char * const cr_regnames[NUM_CR_REGS] = {
919 "status", "estatus", "bstatus", "ienable",
920 "ipending", "cpuid", "res6", "exception",
921 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
922 "badaddr", "config", "mpubase", "mpuacc",
923 "res16", "res17", "res18", "res19",
924 "res20", "res21", "res22", "res23",
925 "res24", "res25", "res26", "res27",
926 "res28", "res29", "res30", "res31",
928 #endif
930 /* generate intermediate code for basic block 'tb'. */
931 static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
933 DisasContext *dc = container_of(dcbase, DisasContext, base);
934 CPUNios2State *env = cs->env_ptr;
935 Nios2CPU *cpu = env_archcpu(env);
936 int page_insns;
938 dc->mem_idx = cpu_mmu_index(env, false);
939 dc->cr_state = cpu->cr_state;
940 dc->tb_flags = dc->base.tb->flags;
941 dc->eic_present = cpu->eic_present;
943 /* Bound the number of insns to execute to those left on the page. */
944 page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
945 dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
948 static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
952 static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
954 tcg_gen_insn_start(dcbase->pc_next);
957 static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
959 DisasContext *dc = container_of(dcbase, DisasContext, base);
960 CPUNios2State *env = cs->env_ptr;
961 const Nios2Instruction *instr;
962 uint32_t code, pc;
963 uint8_t op;
965 pc = dc->base.pc_next;
966 dc->pc = pc;
967 dc->base.pc_next = pc + 4;
969 /* Decode an instruction */
970 code = cpu_ldl_code(env, pc);
971 op = get_opcode(code);
973 if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
974 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
975 return;
978 dc->sink = NULL;
980 instr = &i_type_instructions[op];
981 instr->handler(dc, code, instr->flags);
984 static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
986 DisasContext *dc = container_of(dcbase, DisasContext, base);
988 /* Indicate where the next block should start */
989 switch (dc->base.is_jmp) {
990 case DISAS_TOO_MANY:
991 gen_goto_tb(dc, 0, dc->base.pc_next);
992 break;
994 case DISAS_UPDATE:
995 /* Save the current PC, and return to the main loop. */
996 tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
997 tcg_gen_exit_tb(NULL, 0);
998 break;
1000 case DISAS_NORETURN:
1001 /* nothing more to generate */
1002 break;
1004 default:
1005 g_assert_not_reached();
1009 static void nios2_tr_disas_log(const DisasContextBase *dcbase,
1010 CPUState *cpu, FILE *logfile)
1012 fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
1013 target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
1016 static const TranslatorOps nios2_tr_ops = {
1017 .init_disas_context = nios2_tr_init_disas_context,
1018 .tb_start = nios2_tr_tb_start,
1019 .insn_start = nios2_tr_insn_start,
1020 .translate_insn = nios2_tr_translate_insn,
1021 .tb_stop = nios2_tr_tb_stop,
1022 .disas_log = nios2_tr_disas_log,
1025 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
1026 target_ulong pc, void *host_pc)
1028 DisasContext dc;
1029 translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base);
1032 void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1034 Nios2CPU *cpu = NIOS2_CPU(cs);
1035 CPUNios2State *env = &cpu->env;
1036 int i;
1038 qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
1040 for (i = 0; i < NUM_GP_REGS; i++) {
1041 qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]);
1042 if ((i + 1) % 4 == 0) {
1043 qemu_fprintf(f, "\n");
1047 #if !defined(CONFIG_USER_ONLY)
1048 int j;
1050 for (i = j = 0; i < NUM_CR_REGS; i++) {
1051 if (!nios2_cr_reserved(&cpu->cr_state[i])) {
1052 qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
1053 if (++j % 4 == 0) {
1054 qemu_fprintf(f, "\n");
1058 if (j % 4 != 0) {
1059 qemu_fprintf(f, "\n");
1061 if (cpu->mmu_present) {
1062 qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
1063 env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
1064 FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
1065 env->mmu.tlbacc_wr);
1067 #endif
1068 qemu_fprintf(f, "\n\n");
1071 void nios2_tcg_init(void)
1073 #ifndef CONFIG_USER_ONLY
1074 TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env,
1075 offsetof(CPUNios2State, regs), "crs");
1077 for (int i = 0; i < NUM_GP_REGS; i++) {
1078 cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
1081 #define offsetof_regs0(N) offsetof(CPUNios2State, shadow_regs[0][N])
1082 #else
1083 #define offsetof_regs0(N) offsetof(CPUNios2State, regs[N])
1084 #endif
1086 for (int i = 0; i < NUM_GP_REGS; i++) {
1087 cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i),
1088 gr_regnames[i]);
1091 #undef offsetof_regs0
1093 cpu_pc = tcg_global_mem_new(cpu_env,
1094 offsetof(CPUNios2State, pc), "pc");