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"
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"
32 #include "exec/cpu_ldst.h"
33 #include "exec/translator.h"
34 #include "qemu/qemu-print.h"
35 #include "semihosting/semihost.h"
37 #define HELPER_H "helper.h"
38 #include "exec/helper-info.c.inc"
42 /* is_jmp field values */
43 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
45 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
46 #define INSTRUCTION(func) \
47 INSTRUCTION_FLG(func, 0)
48 #define INSTRUCTION_NOP() \
49 INSTRUCTION_FLG(nop, 0)
50 #define INSTRUCTION_UNIMPLEMENTED() \
51 INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
52 #define INSTRUCTION_ILLEGAL() \
53 INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
55 /* Special R-Type instruction opcode */
56 #define INSN_R_TYPE 0x3A
58 /* I-Type instruction parsing */
69 #define I_TYPE(instr, code) \
70 InstrIType (instr) = { \
71 .op = extract32((code), 0, 6), \
72 .imm16.u = extract32((code), 6, 16), \
73 .b = extract32((code), 22, 5), \
74 .a = extract32((code), 27, 5), \
77 typedef target_ulong
ImmFromIType(const InstrIType
*);
79 static target_ulong
imm_unsigned(const InstrIType
*i
)
84 static target_ulong
imm_signed(const InstrIType
*i
)
89 static target_ulong
imm_shifted(const InstrIType
*i
)
91 return i
->imm16
.u
<< 16;
94 /* R-Type instruction parsing */
104 #define R_TYPE(instr, code) \
105 InstrRType (instr) = { \
106 .op = extract32((code), 0, 6), \
107 .imm5 = extract32((code), 6, 5), \
108 .opx = extract32((code), 11, 6), \
109 .c = extract32((code), 17, 5), \
110 .b = extract32((code), 22, 5), \
111 .a = extract32((code), 27, 5), \
114 /* J-Type instruction parsing */
120 #define J_TYPE(instr, code) \
121 InstrJType (instr) = { \
122 .op = extract32((code), 0, 6), \
123 .imm26 = extract32((code), 6, 26), \
126 typedef void GenFn2i(TCGv
, TCGv
, target_long
);
127 typedef void GenFn3(TCGv
, TCGv
, TCGv
);
128 typedef void GenFn4(TCGv
, TCGv
, TCGv
, TCGv
);
130 typedef struct DisasContext
{
131 DisasContextBase base
;
136 const ControlRegState
*cr_state
;
140 static TCGv cpu_R
[NUM_GP_REGS
];
142 #ifndef CONFIG_USER_ONLY
143 static TCGv cpu_crs_R
[NUM_GP_REGS
];
146 typedef struct Nios2Instruction
{
147 void (*handler
)(DisasContext
*dc
, uint32_t code
, uint32_t flags
);
151 static uint8_t get_opcode(uint32_t code
)
157 static uint8_t get_opxcode(uint32_t code
)
163 static TCGv
load_gpr(DisasContext
*dc
, unsigned reg
)
165 assert(reg
< NUM_GP_REGS
);
168 * With shadow register sets, register r0 does not necessarily contain 0,
169 * but it is overwhelmingly likely that it does -- software is supposed
170 * to have set r0 to 0 in every shadow register set before use.
172 if (unlikely(reg
== R_ZERO
) && FIELD_EX32(dc
->tb_flags
, TBFLAGS
, R0_0
)) {
173 return tcg_constant_tl(0);
175 if (FIELD_EX32(dc
->tb_flags
, TBFLAGS
, CRS0
)) {
178 #ifdef CONFIG_USER_ONLY
179 g_assert_not_reached();
181 return cpu_crs_R
[reg
];
185 static TCGv
dest_gpr(DisasContext
*dc
, unsigned reg
)
187 assert(reg
< NUM_GP_REGS
);
190 * The spec for shadow register sets isn't clear, but we assume that
191 * writes to r0 are discarded regardless of CRS.
193 if (unlikely(reg
== R_ZERO
)) {
194 if (dc
->sink
== NULL
) {
195 dc
->sink
= tcg_temp_new();
199 if (FIELD_EX32(dc
->tb_flags
, TBFLAGS
, CRS0
)) {
202 #ifdef CONFIG_USER_ONLY
203 g_assert_not_reached();
205 return cpu_crs_R
[reg
];
209 static void t_gen_helper_raise_exception(DisasContext
*dc
, uint32_t index
)
211 /* Note that PC is advanced for all hardware exceptions. */
212 tcg_gen_movi_tl(cpu_pc
, dc
->base
.pc_next
);
213 gen_helper_raise_exception(cpu_env
, tcg_constant_i32(index
));
214 dc
->base
.is_jmp
= DISAS_NORETURN
;
217 static void gen_goto_tb(DisasContext
*dc
, int n
, uint32_t dest
)
219 const TranslationBlock
*tb
= dc
->base
.tb
;
221 if (translator_use_goto_tb(&dc
->base
, dest
)) {
223 tcg_gen_movi_tl(cpu_pc
, dest
);
224 tcg_gen_exit_tb(tb
, n
);
226 tcg_gen_movi_tl(cpu_pc
, dest
);
227 tcg_gen_lookup_and_goto_ptr();
229 dc
->base
.is_jmp
= DISAS_NORETURN
;
232 static void gen_jumpr(DisasContext
*dc
, int regno
, bool is_call
)
234 TCGLabel
*l
= gen_new_label();
235 TCGv test
= tcg_temp_new();
236 TCGv dest
= load_gpr(dc
, regno
);
238 tcg_gen_andi_tl(test
, dest
, 3);
239 tcg_gen_brcondi_tl(TCG_COND_NE
, test
, 0, l
);
241 tcg_gen_mov_tl(cpu_pc
, dest
);
243 tcg_gen_movi_tl(dest_gpr(dc
, R_RA
), dc
->base
.pc_next
);
245 tcg_gen_lookup_and_goto_ptr();
248 tcg_gen_st_tl(dest
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_BADADDR
]));
249 t_gen_helper_raise_exception(dc
, EXCP_UNALIGND
);
251 dc
->base
.is_jmp
= DISAS_NORETURN
;
254 static void gen_excp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
256 t_gen_helper_raise_exception(dc
, flags
);
259 static bool gen_check_supervisor(DisasContext
*dc
)
261 if (FIELD_EX32(dc
->tb_flags
, TBFLAGS
, U
)) {
262 /* CPU in user mode, privileged instruction called, stop. */
263 t_gen_helper_raise_exception(dc
, EXCP_SUPERI
);
270 * Used as a placeholder for all instructions which do not have
271 * an effect on the simulator (e.g. flush, sync)
273 static void nop(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
275 /* Nothing to do here */
279 * J-Type instructions
281 static void jmpi(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
284 gen_goto_tb(dc
, 0, (dc
->pc
& 0xF0000000) | (instr
.imm26
<< 2));
287 static void call(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
289 tcg_gen_movi_tl(dest_gpr(dc
, R_RA
), dc
->base
.pc_next
);
290 jmpi(dc
, code
, flags
);
294 * I-Type instructions
296 /* Load instructions */
297 static void gen_ldx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
301 TCGv addr
= tcg_temp_new();
302 TCGv data
= dest_gpr(dc
, instr
.b
);
304 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
305 #ifdef CONFIG_USER_ONLY
310 tcg_gen_qemu_ld_tl(data
, addr
, dc
->mem_idx
, flags
);
313 /* Store instructions */
314 static void gen_stx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
317 TCGv val
= load_gpr(dc
, instr
.b
);
319 TCGv addr
= tcg_temp_new();
320 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
321 #ifdef CONFIG_USER_ONLY
326 tcg_gen_qemu_st_tl(val
, addr
, dc
->mem_idx
, flags
);
329 /* Branch instructions */
330 static void br(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
334 gen_goto_tb(dc
, 0, dc
->base
.pc_next
+ (instr
.imm16
.s
& -4));
337 static void gen_bxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
341 TCGLabel
*l1
= gen_new_label();
342 tcg_gen_brcond_tl(flags
, load_gpr(dc
, instr
.a
), load_gpr(dc
, instr
.b
), l1
);
343 gen_goto_tb(dc
, 0, dc
->base
.pc_next
);
345 gen_goto_tb(dc
, 1, dc
->base
.pc_next
+ (instr
.imm16
.s
& -4));
348 /* Comparison instructions */
349 static void do_i_cmpxx(DisasContext
*dc
, uint32_t insn
,
350 TCGCond cond
, ImmFromIType
*imm
)
353 tcg_gen_setcondi_tl(cond
, dest_gpr(dc
, instr
.b
),
354 load_gpr(dc
, instr
.a
), imm(&instr
));
357 #define gen_i_cmpxx(fname, imm) \
358 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
359 { do_i_cmpxx(dc, code, flags, imm); }
361 gen_i_cmpxx(gen_cmpxxsi
, imm_signed
)
362 gen_i_cmpxx(gen_cmpxxui
, imm_unsigned
)
364 /* Math/logic instructions */
365 static void do_i_math_logic(DisasContext
*dc
, uint32_t insn
,
366 GenFn2i
*fn
, ImmFromIType
*imm
,
372 if (unlikely(instr
.b
== R_ZERO
)) {
373 /* Store to R_ZERO is ignored -- this catches the canonical NOP. */
379 if (instr
.a
== R_ZERO
&& FIELD_EX32(dc
->tb_flags
, TBFLAGS
, R0_0
)) {
380 /* This catches the canonical expansions of movi and movhi. */
381 tcg_gen_movi_tl(dest_gpr(dc
, instr
.b
), x_op_0_eq_x
? val
: 0);
383 fn(dest_gpr(dc
, instr
.b
), load_gpr(dc
, instr
.a
), val
);
387 #define gen_i_math_logic(fname, insn, x_op_0, imm) \
388 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
389 { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); }
391 gen_i_math_logic(addi
, addi
, 1, imm_signed
)
392 gen_i_math_logic(muli
, muli
, 0, imm_signed
)
394 gen_i_math_logic(andi
, andi
, 0, imm_unsigned
)
395 gen_i_math_logic(ori
, ori
, 1, imm_unsigned
)
396 gen_i_math_logic(xori
, xori
, 1, imm_unsigned
)
398 gen_i_math_logic(andhi
, andi
, 0, imm_shifted
)
399 gen_i_math_logic(orhi
, ori
, 1, imm_shifted
)
400 gen_i_math_logic(xorhi
, xori
, 1, imm_shifted
)
402 /* rB <- prs.rA + sigma(IMM16) */
403 static void rdprs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
405 if (!dc
->eic_present
) {
406 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
409 if (!gen_check_supervisor(dc
)) {
413 #ifdef CONFIG_USER_ONLY
414 g_assert_not_reached();
417 TCGv dest
= dest_gpr(dc
, instr
.b
);
418 gen_helper_rdprs(dest
, cpu_env
, tcg_constant_i32(instr
.a
));
419 tcg_gen_addi_tl(dest
, dest
, instr
.imm16
.s
);
423 /* Prototype only, defined below */
424 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
,
427 static const Nios2Instruction i_type_instructions
[] = {
428 INSTRUCTION(call
), /* call */
429 INSTRUCTION(jmpi
), /* jmpi */
430 INSTRUCTION_ILLEGAL(),
431 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbu */
432 INSTRUCTION(addi
), /* addi */
433 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stb */
434 INSTRUCTION(br
), /* br */
435 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldb */
436 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_GE
), /* cmpgei */
437 INSTRUCTION_ILLEGAL(),
438 INSTRUCTION_ILLEGAL(),
439 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhu */
440 INSTRUCTION(andi
), /* andi */
441 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sth */
442 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GE
), /* bge */
443 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldh */
444 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_LT
), /* cmplti */
445 INSTRUCTION_ILLEGAL(),
446 INSTRUCTION_ILLEGAL(),
447 INSTRUCTION_NOP(), /* initda */
448 INSTRUCTION(ori
), /* ori */
449 INSTRUCTION_FLG(gen_stx
, MO_UL
), /* stw */
450 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LT
), /* blt */
451 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldw */
452 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_NE
), /* cmpnei */
453 INSTRUCTION_ILLEGAL(),
454 INSTRUCTION_ILLEGAL(),
455 INSTRUCTION_NOP(), /* flushda */
456 INSTRUCTION(xori
), /* xori */
457 INSTRUCTION_ILLEGAL(),
458 INSTRUCTION_FLG(gen_bxx
, TCG_COND_NE
), /* bne */
459 INSTRUCTION_ILLEGAL(),
460 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_EQ
), /* cmpeqi */
461 INSTRUCTION_ILLEGAL(),
462 INSTRUCTION_ILLEGAL(),
463 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbuio */
464 INSTRUCTION(muli
), /* muli */
465 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stbio */
466 INSTRUCTION_FLG(gen_bxx
, TCG_COND_EQ
), /* beq */
467 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldbio */
468 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_GEU
), /* cmpgeui */
469 INSTRUCTION_ILLEGAL(),
470 INSTRUCTION_ILLEGAL(),
471 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhuio */
472 INSTRUCTION(andhi
), /* andhi */
473 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sthio */
474 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GEU
), /* bgeu */
475 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldhio */
476 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_LTU
), /* cmpltui */
477 INSTRUCTION_ILLEGAL(),
478 INSTRUCTION_UNIMPLEMENTED(), /* custom */
479 INSTRUCTION_NOP(), /* initd */
480 INSTRUCTION(orhi
), /* orhi */
481 INSTRUCTION_FLG(gen_stx
, MO_SL
), /* stwio */
482 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LTU
), /* bltu */
483 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldwio */
484 INSTRUCTION(rdprs
), /* rdprs */
485 INSTRUCTION_ILLEGAL(),
486 INSTRUCTION_FLG(handle_r_type_instr
, 0), /* R-Type */
487 INSTRUCTION_NOP(), /* flushd */
488 INSTRUCTION(xorhi
), /* xorhi */
489 INSTRUCTION_ILLEGAL(),
490 INSTRUCTION_ILLEGAL(),
491 INSTRUCTION_ILLEGAL(),
495 * R-Type instructions
501 static void eret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
503 if (!gen_check_supervisor(dc
)) {
507 #ifdef CONFIG_USER_ONLY
508 g_assert_not_reached();
510 if (FIELD_EX32(dc
->tb_flags
, TBFLAGS
, CRS0
)) {
511 TCGv tmp
= tcg_temp_new();
512 tcg_gen_ld_tl(tmp
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_ESTATUS
]));
513 gen_helper_eret(cpu_env
, tmp
, load_gpr(dc
, R_EA
));
515 gen_helper_eret(cpu_env
, load_gpr(dc
, R_SSTATUS
), load_gpr(dc
, R_EA
));
517 dc
->base
.is_jmp
= DISAS_NORETURN
;
522 static void ret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
524 gen_jumpr(dc
, R_RA
, false);
531 static void bret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
533 if (!gen_check_supervisor(dc
)) {
537 #ifdef CONFIG_USER_ONLY
538 g_assert_not_reached();
540 TCGv tmp
= tcg_temp_new();
541 tcg_gen_ld_tl(tmp
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_BSTATUS
]));
542 gen_helper_eret(cpu_env
, tmp
, load_gpr(dc
, R_BA
));
544 dc
->base
.is_jmp
= DISAS_NORETURN
;
549 static void jmp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
553 gen_jumpr(dc
, instr
.a
, false);
557 static void nextpc(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
561 tcg_gen_movi_tl(dest_gpr(dc
, instr
.c
), dc
->base
.pc_next
);
568 static void callr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
572 gen_jumpr(dc
, instr
.a
, true);
576 static void rdctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
578 if (!gen_check_supervisor(dc
)) {
582 #ifdef CONFIG_USER_ONLY
583 g_assert_not_reached();
586 TCGv t1
, t2
, dest
= dest_gpr(dc
, instr
.c
);
588 /* Reserved registers read as zero. */
589 if (nios2_cr_reserved(&dc
->cr_state
[instr
.imm5
])) {
590 tcg_gen_movi_tl(dest
, 0);
594 switch (instr
.imm5
) {
597 * The value of the ipending register is synthetic.
598 * In hw, this is the AND of a set of hardware irq lines
599 * with the ienable register. In qemu, we re-use the space
600 * of CR_IPENDING to store the set of irq lines, and so we
601 * must perform the AND here, and anywhere else we need the
602 * guest value of ipending.
606 tcg_gen_ld_tl(t1
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_IPENDING
]));
607 tcg_gen_ld_tl(t2
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_IENABLE
]));
608 tcg_gen_and_tl(dest
, t1
, t2
);
611 tcg_gen_ld_tl(dest
, cpu_env
,
612 offsetof(CPUNios2State
, ctrl
[instr
.imm5
]));
619 static void wrctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
621 if (!gen_check_supervisor(dc
)) {
625 #ifdef CONFIG_USER_ONLY
626 g_assert_not_reached();
629 TCGv v
= load_gpr(dc
, instr
.a
);
630 uint32_t ofs
= offsetof(CPUNios2State
, ctrl
[instr
.imm5
]);
631 uint32_t wr
= dc
->cr_state
[instr
.imm5
].writable
;
632 uint32_t ro
= dc
->cr_state
[instr
.imm5
].readonly
;
634 /* Skip reserved or readonly registers. */
639 switch (instr
.imm5
) {
641 gen_helper_mmu_write_pteaddr(cpu_env
, v
);
644 gen_helper_mmu_write_tlbacc(cpu_env
, v
);
647 gen_helper_mmu_write_tlbmisc(cpu_env
, v
);
651 /* If interrupts were enabled using WRCTL, trigger them. */
652 dc
->base
.is_jmp
= DISAS_UPDATE
;
656 /* The register is entirely writable. */
657 tcg_gen_st_tl(v
, cpu_env
, ofs
);
660 * The register is partially read-only or reserved:
663 TCGv n
= tcg_temp_new();
665 tcg_gen_andi_tl(n
, v
, wr
);
668 TCGv o
= tcg_temp_new();
669 tcg_gen_ld_tl(o
, cpu_env
, ofs
);
670 tcg_gen_andi_tl(o
, o
, ro
);
671 tcg_gen_or_tl(n
, n
, o
);
674 tcg_gen_st_tl(n
, cpu_env
, ofs
);
682 static void wrprs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
684 if (!dc
->eic_present
) {
685 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
688 if (!gen_check_supervisor(dc
)) {
692 #ifdef CONFIG_USER_ONLY
693 g_assert_not_reached();
696 gen_helper_wrprs(cpu_env
, tcg_constant_i32(instr
.c
),
697 load_gpr(dc
, instr
.a
));
699 * The expected write to PRS[r0] is 0, from CRS[r0].
700 * If not, and CRS == PRS (which we cannot tell from here),
701 * we may now have a non-zero value in our current r0.
702 * By ending the TB, we re-evaluate tb_flags and find out.
705 && (instr
.a
!= 0 || !FIELD_EX32(dc
->tb_flags
, TBFLAGS
, R0_0
))) {
706 dc
->base
.is_jmp
= DISAS_UPDATE
;
711 /* Comparison instructions */
712 static void gen_cmpxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
715 tcg_gen_setcond_tl(flags
, dest_gpr(dc
, instr
.c
),
716 load_gpr(dc
, instr
.a
), load_gpr(dc
, instr
.b
));
719 /* Math/logic instructions */
720 static void do_ri_math_logic(DisasContext
*dc
, uint32_t insn
, GenFn2i
*fn
)
723 fn(dest_gpr(dc
, instr
.c
), load_gpr(dc
, instr
.a
), instr
.imm5
);
726 static void do_rr_math_logic(DisasContext
*dc
, uint32_t insn
, GenFn3
*fn
)
729 fn(dest_gpr(dc
, instr
.c
), load_gpr(dc
, instr
.a
), load_gpr(dc
, instr
.b
));
732 #define gen_ri_math_logic(fname, insn) \
733 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
734 { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); }
736 #define gen_rr_math_logic(fname, insn) \
737 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
738 { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); }
740 gen_rr_math_logic(add
, add
)
741 gen_rr_math_logic(sub
, sub
)
742 gen_rr_math_logic(mul
, mul
)
744 gen_rr_math_logic(and, and)
745 gen_rr_math_logic(or, or)
746 gen_rr_math_logic(xor, xor)
747 gen_rr_math_logic(nor
, nor
)
749 gen_ri_math_logic(srai
, sari
)
750 gen_ri_math_logic(srli
, shri
)
751 gen_ri_math_logic(slli
, shli
)
752 gen_ri_math_logic(roli
, rotli
)
754 static void do_rr_mul_high(DisasContext
*dc
, uint32_t insn
, GenFn4
*fn
)
757 TCGv discard
= tcg_temp_new();
759 fn(discard
, dest_gpr(dc
, instr
.c
),
760 load_gpr(dc
, instr
.a
), load_gpr(dc
, instr
.b
));
763 #define gen_rr_mul_high(fname, insn) \
764 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
765 { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); }
767 gen_rr_mul_high(mulxss
, muls2
)
768 gen_rr_mul_high(mulxuu
, mulu2
)
769 gen_rr_mul_high(mulxsu
, mulsu2
)
771 static void do_rr_shift(DisasContext
*dc
, uint32_t insn
, GenFn3
*fn
)
774 TCGv sh
= tcg_temp_new();
776 tcg_gen_andi_tl(sh
, load_gpr(dc
, instr
.b
), 31);
777 fn(dest_gpr(dc
, instr
.c
), load_gpr(dc
, instr
.a
), sh
);
780 #define gen_rr_shift(fname, insn) \
781 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
782 { do_rr_shift(dc, code, tcg_gen_##insn##_tl); }
784 gen_rr_shift(sra
, sar
)
785 gen_rr_shift(srl
, shr
)
786 gen_rr_shift(sll
, shl
)
787 gen_rr_shift(rol
, rotl
)
788 gen_rr_shift(ror
, rotr
)
790 static void divs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
792 R_TYPE(instr
, (code
));
793 gen_helper_divs(dest_gpr(dc
, instr
.c
), cpu_env
,
794 load_gpr(dc
, instr
.a
), load_gpr(dc
, instr
.b
));
797 static void divu(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
799 R_TYPE(instr
, (code
));
800 gen_helper_divu(dest_gpr(dc
, instr
.c
), cpu_env
,
801 load_gpr(dc
, instr
.a
), load_gpr(dc
, instr
.b
));
804 static void trap(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
806 #ifdef CONFIG_USER_ONLY
808 * The imm5 field is not stored anywhere on real hw; the kernel
809 * has to load the insn and extract the field. But we can make
810 * things easier for cpu_loop if we pop this into env->error_code.
813 tcg_gen_st_i32(tcg_constant_i32(instr
.imm5
), cpu_env
,
814 offsetof(CPUNios2State
, error_code
));
816 t_gen_helper_raise_exception(dc
, EXCP_TRAP
);
819 static void gen_break(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
821 #ifndef CONFIG_USER_ONLY
822 /* The semihosting instruction is "break 1". */
823 bool is_user
= FIELD_EX32(dc
->tb_flags
, TBFLAGS
, U
);
825 if (semihosting_enabled(is_user
) && instr
.imm5
== 1) {
826 t_gen_helper_raise_exception(dc
, EXCP_SEMIHOST
);
831 t_gen_helper_raise_exception(dc
, EXCP_BREAK
);
834 static const Nios2Instruction r_type_instructions
[] = {
835 INSTRUCTION_ILLEGAL(),
836 INSTRUCTION(eret
), /* eret */
837 INSTRUCTION(roli
), /* roli */
838 INSTRUCTION(rol
), /* rol */
839 INSTRUCTION_NOP(), /* flushp */
840 INSTRUCTION(ret
), /* ret */
841 INSTRUCTION(nor
), /* nor */
842 INSTRUCTION(mulxuu
), /* mulxuu */
843 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GE
), /* cmpge */
844 INSTRUCTION(bret
), /* bret */
845 INSTRUCTION_ILLEGAL(),
846 INSTRUCTION(ror
), /* ror */
847 INSTRUCTION_NOP(), /* flushi */
848 INSTRUCTION(jmp
), /* jmp */
849 INSTRUCTION(and), /* and */
850 INSTRUCTION_ILLEGAL(),
851 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LT
), /* cmplt */
852 INSTRUCTION_ILLEGAL(),
853 INSTRUCTION(slli
), /* slli */
854 INSTRUCTION(sll
), /* sll */
855 INSTRUCTION(wrprs
), /* wrprs */
856 INSTRUCTION_ILLEGAL(),
857 INSTRUCTION(or), /* or */
858 INSTRUCTION(mulxsu
), /* mulxsu */
859 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_NE
), /* cmpne */
860 INSTRUCTION_ILLEGAL(),
861 INSTRUCTION(srli
), /* srli */
862 INSTRUCTION(srl
), /* srl */
863 INSTRUCTION(nextpc
), /* nextpc */
864 INSTRUCTION(callr
), /* callr */
865 INSTRUCTION(xor), /* xor */
866 INSTRUCTION(mulxss
), /* mulxss */
867 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_EQ
), /* cmpeq */
868 INSTRUCTION_ILLEGAL(),
869 INSTRUCTION_ILLEGAL(),
870 INSTRUCTION_ILLEGAL(),
871 INSTRUCTION(divu
), /* divu */
872 INSTRUCTION(divs
), /* div */
873 INSTRUCTION(rdctl
), /* rdctl */
874 INSTRUCTION(mul
), /* mul */
875 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GEU
), /* cmpgeu */
876 INSTRUCTION_NOP(), /* initi */
877 INSTRUCTION_ILLEGAL(),
878 INSTRUCTION_ILLEGAL(),
879 INSTRUCTION_ILLEGAL(),
880 INSTRUCTION(trap
), /* trap */
881 INSTRUCTION(wrctl
), /* wrctl */
882 INSTRUCTION_ILLEGAL(),
883 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LTU
), /* cmpltu */
884 INSTRUCTION(add
), /* add */
885 INSTRUCTION_ILLEGAL(),
886 INSTRUCTION_ILLEGAL(),
887 INSTRUCTION(gen_break
), /* break */
888 INSTRUCTION_ILLEGAL(),
889 INSTRUCTION(nop
), /* nop */
890 INSTRUCTION_ILLEGAL(),
891 INSTRUCTION_ILLEGAL(),
892 INSTRUCTION(sub
), /* sub */
893 INSTRUCTION(srai
), /* srai */
894 INSTRUCTION(sra
), /* sra */
895 INSTRUCTION_ILLEGAL(),
896 INSTRUCTION_ILLEGAL(),
897 INSTRUCTION_ILLEGAL(),
898 INSTRUCTION_ILLEGAL(),
901 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
904 const Nios2Instruction
*instr
;
906 opx
= get_opxcode(code
);
907 if (unlikely(opx
>= ARRAY_SIZE(r_type_instructions
))) {
911 instr
= &r_type_instructions
[opx
];
912 instr
->handler(dc
, code
, instr
->flags
);
917 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
920 static const char * const gr_regnames
[NUM_GP_REGS
] = {
921 "zero", "at", "r2", "r3",
922 "r4", "r5", "r6", "r7",
923 "r8", "r9", "r10", "r11",
924 "r12", "r13", "r14", "r15",
925 "r16", "r17", "r18", "r19",
926 "r20", "r21", "r22", "r23",
927 "et", "bt", "gp", "sp",
928 "fp", "ea", "ba", "ra",
931 #ifndef CONFIG_USER_ONLY
932 static const char * const cr_regnames
[NUM_CR_REGS
] = {
933 "status", "estatus", "bstatus", "ienable",
934 "ipending", "cpuid", "res6", "exception",
935 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
936 "badaddr", "config", "mpubase", "mpuacc",
937 "res16", "res17", "res18", "res19",
938 "res20", "res21", "res22", "res23",
939 "res24", "res25", "res26", "res27",
940 "res28", "res29", "res30", "res31",
944 /* generate intermediate code for basic block 'tb'. */
945 static void nios2_tr_init_disas_context(DisasContextBase
*dcbase
, CPUState
*cs
)
947 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
948 CPUNios2State
*env
= cs
->env_ptr
;
949 Nios2CPU
*cpu
= env_archcpu(env
);
952 dc
->mem_idx
= cpu_mmu_index(env
, false);
953 dc
->cr_state
= cpu
->cr_state
;
954 dc
->tb_flags
= dc
->base
.tb
->flags
;
955 dc
->eic_present
= cpu
->eic_present
;
957 /* Bound the number of insns to execute to those left on the page. */
958 page_insns
= -(dc
->base
.pc_first
| TARGET_PAGE_MASK
) / 4;
959 dc
->base
.max_insns
= MIN(page_insns
, dc
->base
.max_insns
);
962 static void nios2_tr_tb_start(DisasContextBase
*db
, CPUState
*cs
)
966 static void nios2_tr_insn_start(DisasContextBase
*dcbase
, CPUState
*cs
)
968 tcg_gen_insn_start(dcbase
->pc_next
);
971 static void nios2_tr_translate_insn(DisasContextBase
*dcbase
, CPUState
*cs
)
973 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
974 CPUNios2State
*env
= cs
->env_ptr
;
975 const Nios2Instruction
*instr
;
979 pc
= dc
->base
.pc_next
;
981 dc
->base
.pc_next
= pc
+ 4;
983 /* Decode an instruction */
984 code
= cpu_ldl_code(env
, pc
);
985 op
= get_opcode(code
);
987 if (unlikely(op
>= ARRAY_SIZE(i_type_instructions
))) {
988 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
994 instr
= &i_type_instructions
[op
];
995 instr
->handler(dc
, code
, instr
->flags
);
998 static void nios2_tr_tb_stop(DisasContextBase
*dcbase
, CPUState
*cs
)
1000 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
1002 /* Indicate where the next block should start */
1003 switch (dc
->base
.is_jmp
) {
1004 case DISAS_TOO_MANY
:
1005 gen_goto_tb(dc
, 0, dc
->base
.pc_next
);
1009 /* Save the current PC, and return to the main loop. */
1010 tcg_gen_movi_tl(cpu_pc
, dc
->base
.pc_next
);
1011 tcg_gen_exit_tb(NULL
, 0);
1014 case DISAS_NORETURN
:
1015 /* nothing more to generate */
1019 g_assert_not_reached();
1023 static void nios2_tr_disas_log(const DisasContextBase
*dcbase
,
1024 CPUState
*cpu
, FILE *logfile
)
1026 fprintf(logfile
, "IN: %s\n", lookup_symbol(dcbase
->pc_first
));
1027 target_disas(logfile
, cpu
, dcbase
->pc_first
, dcbase
->tb
->size
);
1030 static const TranslatorOps nios2_tr_ops
= {
1031 .init_disas_context
= nios2_tr_init_disas_context
,
1032 .tb_start
= nios2_tr_tb_start
,
1033 .insn_start
= nios2_tr_insn_start
,
1034 .translate_insn
= nios2_tr_translate_insn
,
1035 .tb_stop
= nios2_tr_tb_stop
,
1036 .disas_log
= nios2_tr_disas_log
,
1039 void gen_intermediate_code(CPUState
*cs
, TranslationBlock
*tb
, int *max_insns
,
1040 target_ulong pc
, void *host_pc
)
1043 translator_loop(cs
, tb
, max_insns
, pc
, host_pc
, &nios2_tr_ops
, &dc
.base
);
1046 void nios2_cpu_dump_state(CPUState
*cs
, FILE *f
, int flags
)
1048 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
1049 CPUNios2State
*env
= &cpu
->env
;
1052 qemu_fprintf(f
, "IN: PC=%x %s\n", env
->pc
, lookup_symbol(env
->pc
));
1054 for (i
= 0; i
< NUM_GP_REGS
; i
++) {
1055 qemu_fprintf(f
, "%9s=%8.8x ", gr_regnames
[i
], env
->regs
[i
]);
1056 if ((i
+ 1) % 4 == 0) {
1057 qemu_fprintf(f
, "\n");
1061 #if !defined(CONFIG_USER_ONLY)
1064 for (i
= j
= 0; i
< NUM_CR_REGS
; i
++) {
1065 if (!nios2_cr_reserved(&cpu
->cr_state
[i
])) {
1066 qemu_fprintf(f
, "%9s=%8.8x ", cr_regnames
[i
], env
->ctrl
[i
]);
1068 qemu_fprintf(f
, "\n");
1073 qemu_fprintf(f
, "\n");
1075 if (cpu
->mmu_present
) {
1076 qemu_fprintf(f
, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
1077 env
->mmu
.pteaddr_wr
& R_CR_PTEADDR_VPN_MASK
,
1078 FIELD_EX32(env
->mmu
.tlbmisc_wr
, CR_TLBMISC
, PID
),
1079 env
->mmu
.tlbacc_wr
);
1082 qemu_fprintf(f
, "\n\n");
1085 void nios2_tcg_init(void)
1087 #ifndef CONFIG_USER_ONLY
1088 TCGv_ptr crs
= tcg_global_mem_new_ptr(cpu_env
,
1089 offsetof(CPUNios2State
, regs
), "crs");
1091 for (int i
= 0; i
< NUM_GP_REGS
; i
++) {
1092 cpu_crs_R
[i
] = tcg_global_mem_new(crs
, 4 * i
, gr_regnames
[i
]);
1095 #define offsetof_regs0(N) offsetof(CPUNios2State, shadow_regs[0][N])
1097 #define offsetof_regs0(N) offsetof(CPUNios2State, regs[N])
1100 for (int i
= 0; i
< NUM_GP_REGS
; i
++) {
1101 cpu_R
[i
] = tcg_global_mem_new(cpu_env
, offsetof_regs0(i
),
1105 #undef offsetof_regs0
1107 cpu_pc
= tcg_global_mem_new(cpu_env
,
1108 offsetof(CPUNios2State
, pc
), "pc");