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 "exec/gen-icount.h"
37 /* is_jmp field values */
38 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
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 #define I_TYPE(instr, code) \
65 .op = extract32((code), 0, 6), \
66 .imm16.u = extract32((code), 6, 16), \
67 .b = extract32((code), 22, 5), \
68 .a = extract32((code), 27, 5), \
71 /* R-Type instruction parsing */
72 #define R_TYPE(instr, code) \
81 .op = extract32((code), 0, 6), \
82 .imm5 = extract32((code), 6, 5), \
83 .opx = extract32((code), 11, 6), \
84 .c = extract32((code), 17, 5), \
85 .b = extract32((code), 22, 5), \
86 .a = extract32((code), 27, 5), \
89 /* J-Type instruction parsing */
90 #define J_TYPE(instr, code) \
95 .op = extract32((code), 0, 6), \
96 .imm26 = extract32((code), 6, 26), \
99 typedef struct DisasContext
{
100 DisasContextBase base
;
106 static TCGv cpu_R
[NUM_GP_REGS
];
109 typedef struct Nios2Instruction
{
110 void (*handler
)(DisasContext
*dc
, uint32_t code
, uint32_t flags
);
114 static uint8_t get_opcode(uint32_t code
)
120 static uint8_t get_opxcode(uint32_t code
)
126 static TCGv
load_zero(DisasContext
*dc
)
129 dc
->zero
= tcg_const_i32(0);
134 static TCGv
load_gpr(DisasContext
*dc
, uint8_t reg
)
136 if (likely(reg
!= R_ZERO
)) {
139 return load_zero(dc
);
143 static void t_gen_helper_raise_exception(DisasContext
*dc
,
146 TCGv_i32 tmp
= tcg_const_i32(index
);
148 tcg_gen_movi_tl(cpu_pc
, dc
->pc
);
149 gen_helper_raise_exception(cpu_env
, tmp
);
150 tcg_temp_free_i32(tmp
);
151 dc
->base
.is_jmp
= DISAS_NORETURN
;
154 static void gen_goto_tb(DisasContext
*dc
, int n
, uint32_t dest
)
156 const TranslationBlock
*tb
= dc
->base
.tb
;
158 if (translator_use_goto_tb(&dc
->base
, dest
)) {
160 tcg_gen_movi_tl(cpu_pc
, dest
);
161 tcg_gen_exit_tb(tb
, n
);
163 tcg_gen_movi_tl(cpu_pc
, dest
);
164 tcg_gen_exit_tb(NULL
, 0);
168 static void gen_excp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
170 t_gen_helper_raise_exception(dc
, flags
);
173 static bool gen_check_supervisor(DisasContext
*dc
)
175 if (dc
->base
.tb
->flags
& CR_STATUS_U
) {
176 /* CPU in user mode, privileged instruction called, stop. */
177 t_gen_helper_raise_exception(dc
, EXCP_SUPERI
);
184 * Used as a placeholder for all instructions which do not have
185 * an effect on the simulator (e.g. flush, sync)
187 static void nop(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
189 /* Nothing to do here */
193 * J-Type instructions
195 static void jmpi(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
198 gen_goto_tb(dc
, 0, (dc
->pc
& 0xF0000000) | (instr
.imm26
<< 2));
199 dc
->base
.is_jmp
= DISAS_NORETURN
;
202 static void call(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
204 tcg_gen_movi_tl(cpu_R
[R_RA
], dc
->base
.pc_next
);
205 jmpi(dc
, code
, flags
);
209 * I-Type instructions
211 /* Load instructions */
212 static void gen_ldx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
216 TCGv addr
= tcg_temp_new();
220 * WARNING: Loads into R_ZERO are ignored, but we must generate the
221 * memory access itself to emulate the CPU precisely. Load
222 * from a protected page to R_ZERO will cause SIGSEGV on
225 if (likely(instr
.b
!= R_ZERO
)) {
226 data
= cpu_R
[instr
.b
];
228 data
= tcg_temp_new();
231 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
232 tcg_gen_qemu_ld_tl(data
, addr
, dc
->mem_idx
, flags
);
234 if (unlikely(instr
.b
== R_ZERO
)) {
241 /* Store instructions */
242 static void gen_stx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
245 TCGv val
= load_gpr(dc
, instr
.b
);
247 TCGv addr
= tcg_temp_new();
248 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
249 tcg_gen_qemu_st_tl(val
, addr
, dc
->mem_idx
, flags
);
253 /* Branch instructions */
254 static void br(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
258 gen_goto_tb(dc
, 0, dc
->base
.pc_next
+ (instr
.imm16
.s
& -4));
259 dc
->base
.is_jmp
= DISAS_NORETURN
;
262 static void gen_bxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
266 TCGLabel
*l1
= gen_new_label();
267 tcg_gen_brcond_tl(flags
, cpu_R
[instr
.a
], cpu_R
[instr
.b
], l1
);
268 gen_goto_tb(dc
, 0, dc
->base
.pc_next
);
270 gen_goto_tb(dc
, 1, dc
->base
.pc_next
+ (instr
.imm16
.s
& -4));
271 dc
->base
.is_jmp
= DISAS_NORETURN
;
274 /* Comparison instructions */
275 #define gen_i_cmpxx(fname, op3) \
276 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
278 I_TYPE(instr, (code)); \
279 tcg_gen_setcondi_tl(flags, cpu_R[instr.b], cpu_R[instr.a], (op3)); \
282 gen_i_cmpxx(gen_cmpxxsi
, instr
.imm16
.s
)
283 gen_i_cmpxx(gen_cmpxxui
, instr
.imm16
.u
)
285 /* Math/logic instructions */
286 #define gen_i_math_logic(fname, insn, resimm, op3) \
287 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
289 I_TYPE(instr, (code)); \
290 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
292 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
293 tcg_gen_movi_tl(cpu_R[instr.b], (resimm) ? (op3) : 0); \
295 tcg_gen_##insn##_tl(cpu_R[instr.b], cpu_R[instr.a], (op3)); \
299 gen_i_math_logic(addi
, addi
, 1, instr
.imm16
.s
)
300 gen_i_math_logic(muli
, muli
, 0, instr
.imm16
.s
)
302 gen_i_math_logic(andi
, andi
, 0, instr
.imm16
.u
)
303 gen_i_math_logic(ori
, ori
, 1, instr
.imm16
.u
)
304 gen_i_math_logic(xori
, xori
, 1, instr
.imm16
.u
)
306 gen_i_math_logic(andhi
, andi
, 0, instr
.imm16
.u
<< 16)
307 gen_i_math_logic(orhi
, ori
, 1, instr
.imm16
.u
<< 16)
308 gen_i_math_logic(xorhi
, xori
, 1, instr
.imm16
.u
<< 16)
310 /* Prototype only, defined below */
311 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
,
314 static const Nios2Instruction i_type_instructions
[] = {
315 INSTRUCTION(call
), /* call */
316 INSTRUCTION(jmpi
), /* jmpi */
317 INSTRUCTION_ILLEGAL(),
318 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbu */
319 INSTRUCTION(addi
), /* addi */
320 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stb */
321 INSTRUCTION(br
), /* br */
322 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldb */
323 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_GE
), /* cmpgei */
324 INSTRUCTION_ILLEGAL(),
325 INSTRUCTION_ILLEGAL(),
326 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhu */
327 INSTRUCTION(andi
), /* andi */
328 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sth */
329 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GE
), /* bge */
330 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldh */
331 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_LT
), /* cmplti */
332 INSTRUCTION_ILLEGAL(),
333 INSTRUCTION_ILLEGAL(),
334 INSTRUCTION_NOP(), /* initda */
335 INSTRUCTION(ori
), /* ori */
336 INSTRUCTION_FLG(gen_stx
, MO_UL
), /* stw */
337 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LT
), /* blt */
338 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldw */
339 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_NE
), /* cmpnei */
340 INSTRUCTION_ILLEGAL(),
341 INSTRUCTION_ILLEGAL(),
342 INSTRUCTION_NOP(), /* flushda */
343 INSTRUCTION(xori
), /* xori */
344 INSTRUCTION_ILLEGAL(),
345 INSTRUCTION_FLG(gen_bxx
, TCG_COND_NE
), /* bne */
346 INSTRUCTION_ILLEGAL(),
347 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_EQ
), /* cmpeqi */
348 INSTRUCTION_ILLEGAL(),
349 INSTRUCTION_ILLEGAL(),
350 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbuio */
351 INSTRUCTION(muli
), /* muli */
352 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stbio */
353 INSTRUCTION_FLG(gen_bxx
, TCG_COND_EQ
), /* beq */
354 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldbio */
355 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_GEU
), /* cmpgeui */
356 INSTRUCTION_ILLEGAL(),
357 INSTRUCTION_ILLEGAL(),
358 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhuio */
359 INSTRUCTION(andhi
), /* andhi */
360 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sthio */
361 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GEU
), /* bgeu */
362 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldhio */
363 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_LTU
), /* cmpltui */
364 INSTRUCTION_ILLEGAL(),
365 INSTRUCTION_UNIMPLEMENTED(), /* custom */
366 INSTRUCTION_NOP(), /* initd */
367 INSTRUCTION(orhi
), /* orhi */
368 INSTRUCTION_FLG(gen_stx
, MO_SL
), /* stwio */
369 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LTU
), /* bltu */
370 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldwio */
371 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
372 INSTRUCTION_ILLEGAL(),
373 INSTRUCTION_FLG(handle_r_type_instr
, 0), /* R-Type */
374 INSTRUCTION_NOP(), /* flushd */
375 INSTRUCTION(xorhi
), /* xorhi */
376 INSTRUCTION_ILLEGAL(),
377 INSTRUCTION_ILLEGAL(),
378 INSTRUCTION_ILLEGAL(),
382 * R-Type instructions
388 static void eret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
390 if (!gen_check_supervisor(dc
)) {
394 #ifdef CONFIG_USER_ONLY
395 g_assert_not_reached();
397 TCGv tmp
= tcg_temp_new();
398 tcg_gen_ld_tl(tmp
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_ESTATUS
]));
399 gen_helper_eret(cpu_env
, tmp
, cpu_R
[R_EA
]);
402 dc
->base
.is_jmp
= DISAS_NORETURN
;
407 static void ret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
409 tcg_gen_mov_tl(cpu_pc
, cpu_R
[R_RA
]);
411 dc
->base
.is_jmp
= DISAS_JUMP
;
418 static void bret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
420 if (!gen_check_supervisor(dc
)) {
424 #ifdef CONFIG_USER_ONLY
425 g_assert_not_reached();
427 TCGv tmp
= tcg_temp_new();
428 tcg_gen_ld_tl(tmp
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_BSTATUS
]));
429 gen_helper_eret(cpu_env
, tmp
, cpu_R
[R_BA
]);
432 dc
->base
.is_jmp
= DISAS_NORETURN
;
437 static void jmp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
441 tcg_gen_mov_tl(cpu_pc
, load_gpr(dc
, instr
.a
));
443 dc
->base
.is_jmp
= DISAS_JUMP
;
447 static void nextpc(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
451 if (likely(instr
.c
!= R_ZERO
)) {
452 tcg_gen_movi_tl(cpu_R
[instr
.c
], dc
->base
.pc_next
);
460 static void callr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
464 tcg_gen_mov_tl(cpu_pc
, load_gpr(dc
, instr
.a
));
465 tcg_gen_movi_tl(cpu_R
[R_RA
], dc
->base
.pc_next
);
467 dc
->base
.is_jmp
= DISAS_JUMP
;
471 static void rdctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
476 if (!gen_check_supervisor(dc
)) {
480 if (unlikely(instr
.c
== R_ZERO
)) {
484 switch (instr
.imm5
) {
487 * The value of the ipending register is synthetic.
488 * In hw, this is the AND of a set of hardware irq lines
489 * with the ienable register. In qemu, we re-use the space
490 * of CR_IPENDING to store the set of irq lines, and so we
491 * must perform the AND here, and anywhere else we need the
492 * guest value of ipending.
496 tcg_gen_ld_tl(t1
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_IPENDING
]));
497 tcg_gen_ld_tl(t2
, cpu_env
, offsetof(CPUNios2State
, ctrl
[CR_IENABLE
]));
498 tcg_gen_and_tl(cpu_R
[instr
.c
], t1
, t2
);
503 tcg_gen_ld_tl(cpu_R
[instr
.c
], cpu_env
,
504 offsetof(CPUNios2State
, ctrl
[instr
.imm5
]));
510 static void wrctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
512 if (!gen_check_supervisor(dc
)) {
516 #ifdef CONFIG_USER_ONLY
517 g_assert_not_reached();
520 TCGv v
= load_gpr(dc
, instr
.a
);
522 switch (instr
.imm5
) {
524 gen_helper_mmu_write_pteaddr(cpu_env
, v
);
527 gen_helper_mmu_write_tlbacc(cpu_env
, v
);
530 gen_helper_mmu_write_tlbmisc(cpu_env
, v
);
533 /* ipending is read only, writes ignored. */
537 /* If interrupts were enabled using WRCTL, trigger them. */
538 dc
->base
.is_jmp
= DISAS_UPDATE
;
541 tcg_gen_st_tl(v
, cpu_env
,
542 offsetof(CPUNios2State
, ctrl
[instr
.imm5
]));
548 /* Comparison instructions */
549 static void gen_cmpxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
552 if (likely(instr
.c
!= R_ZERO
)) {
553 tcg_gen_setcond_tl(flags
, cpu_R
[instr
.c
], cpu_R
[instr
.a
],
558 /* Math/logic instructions */
559 #define gen_r_math_logic(fname, insn, op3) \
560 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
562 R_TYPE(instr, (code)); \
563 if (likely(instr.c != R_ZERO)) { \
564 tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), (op3)); \
568 gen_r_math_logic(add
, add_tl
, load_gpr(dc
, instr
.b
))
569 gen_r_math_logic(sub
, sub_tl
, load_gpr(dc
, instr
.b
))
570 gen_r_math_logic(mul
, mul_tl
, load_gpr(dc
, instr
.b
))
572 gen_r_math_logic(and, and_tl
, load_gpr(dc
, instr
.b
))
573 gen_r_math_logic(or, or_tl
, load_gpr(dc
, instr
.b
))
574 gen_r_math_logic(xor, xor_tl
, load_gpr(dc
, instr
.b
))
575 gen_r_math_logic(nor
, nor_tl
, load_gpr(dc
, instr
.b
))
577 gen_r_math_logic(srai
, sari_tl
, instr
.imm5
)
578 gen_r_math_logic(srli
, shri_tl
, instr
.imm5
)
579 gen_r_math_logic(slli
, shli_tl
, instr
.imm5
)
580 gen_r_math_logic(roli
, rotli_tl
, instr
.imm5
)
582 #define gen_r_mul(fname, insn) \
583 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
585 R_TYPE(instr, (code)); \
586 if (likely(instr.c != R_ZERO)) { \
587 TCGv t0 = tcg_temp_new(); \
588 tcg_gen_##insn(t0, cpu_R[instr.c], \
589 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
594 gen_r_mul(mulxss
, muls2_tl
)
595 gen_r_mul(mulxuu
, mulu2_tl
)
596 gen_r_mul(mulxsu
, mulsu2_tl
)
598 #define gen_r_shift_s(fname, insn) \
599 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
601 R_TYPE(instr, (code)); \
602 if (likely(instr.c != R_ZERO)) { \
603 TCGv t0 = tcg_temp_new(); \
604 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
605 tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
610 gen_r_shift_s(sra
, sar_tl
)
611 gen_r_shift_s(srl
, shr_tl
)
612 gen_r_shift_s(sll
, shl_tl
)
613 gen_r_shift_s(rol
, rotl_tl
)
614 gen_r_shift_s(ror
, rotr_tl
)
616 static void divs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
618 R_TYPE(instr
, (code
));
620 /* Stores into R_ZERO are ignored */
621 if (unlikely(instr
.c
== R_ZERO
)) {
625 TCGv t0
= tcg_temp_new();
626 TCGv t1
= tcg_temp_new();
627 TCGv t2
= tcg_temp_new();
628 TCGv t3
= tcg_temp_new();
630 tcg_gen_ext32s_tl(t0
, load_gpr(dc
, instr
.a
));
631 tcg_gen_ext32s_tl(t1
, load_gpr(dc
, instr
.b
));
632 tcg_gen_setcondi_tl(TCG_COND_EQ
, t2
, t0
, INT_MIN
);
633 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, -1);
634 tcg_gen_and_tl(t2
, t2
, t3
);
635 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, 0);
636 tcg_gen_or_tl(t2
, t2
, t3
);
637 tcg_gen_movi_tl(t3
, 0);
638 tcg_gen_movcond_tl(TCG_COND_NE
, t1
, t2
, t3
, t2
, t1
);
639 tcg_gen_div_tl(cpu_R
[instr
.c
], t0
, t1
);
640 tcg_gen_ext32s_tl(cpu_R
[instr
.c
], cpu_R
[instr
.c
]);
648 static void divu(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
650 R_TYPE(instr
, (code
));
652 /* Stores into R_ZERO are ignored */
653 if (unlikely(instr
.c
== R_ZERO
)) {
657 TCGv t0
= tcg_temp_new();
658 TCGv t1
= tcg_temp_new();
659 TCGv t2
= tcg_const_tl(0);
660 TCGv t3
= tcg_const_tl(1);
662 tcg_gen_ext32u_tl(t0
, load_gpr(dc
, instr
.a
));
663 tcg_gen_ext32u_tl(t1
, load_gpr(dc
, instr
.b
));
664 tcg_gen_movcond_tl(TCG_COND_EQ
, t1
, t1
, t2
, t3
, t1
);
665 tcg_gen_divu_tl(cpu_R
[instr
.c
], t0
, t1
);
666 tcg_gen_ext32s_tl(cpu_R
[instr
.c
], cpu_R
[instr
.c
]);
674 static void trap(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
676 #ifdef CONFIG_USER_ONLY
678 * The imm5 field is not stored anywhere on real hw; the kernel
679 * has to load the insn and extract the field. But we can make
680 * things easier for cpu_loop if we pop this into env->error_code.
683 tcg_gen_st_i32(tcg_constant_i32(instr
.imm5
), cpu_env
,
684 offsetof(CPUNios2State
, error_code
));
686 t_gen_helper_raise_exception(dc
, EXCP_TRAP
);
689 static const Nios2Instruction r_type_instructions
[] = {
690 INSTRUCTION_ILLEGAL(),
691 INSTRUCTION(eret
), /* eret */
692 INSTRUCTION(roli
), /* roli */
693 INSTRUCTION(rol
), /* rol */
694 INSTRUCTION_NOP(), /* flushp */
695 INSTRUCTION(ret
), /* ret */
696 INSTRUCTION(nor
), /* nor */
697 INSTRUCTION(mulxuu
), /* mulxuu */
698 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GE
), /* cmpge */
699 INSTRUCTION(bret
), /* bret */
700 INSTRUCTION_ILLEGAL(),
701 INSTRUCTION(ror
), /* ror */
702 INSTRUCTION_NOP(), /* flushi */
703 INSTRUCTION(jmp
), /* jmp */
704 INSTRUCTION(and), /* and */
705 INSTRUCTION_ILLEGAL(),
706 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LT
), /* cmplt */
707 INSTRUCTION_ILLEGAL(),
708 INSTRUCTION(slli
), /* slli */
709 INSTRUCTION(sll
), /* sll */
710 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
711 INSTRUCTION_ILLEGAL(),
712 INSTRUCTION(or), /* or */
713 INSTRUCTION(mulxsu
), /* mulxsu */
714 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_NE
), /* cmpne */
715 INSTRUCTION_ILLEGAL(),
716 INSTRUCTION(srli
), /* srli */
717 INSTRUCTION(srl
), /* srl */
718 INSTRUCTION(nextpc
), /* nextpc */
719 INSTRUCTION(callr
), /* callr */
720 INSTRUCTION(xor), /* xor */
721 INSTRUCTION(mulxss
), /* mulxss */
722 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_EQ
), /* cmpeq */
723 INSTRUCTION_ILLEGAL(),
724 INSTRUCTION_ILLEGAL(),
725 INSTRUCTION_ILLEGAL(),
726 INSTRUCTION(divu
), /* divu */
727 INSTRUCTION(divs
), /* div */
728 INSTRUCTION(rdctl
), /* rdctl */
729 INSTRUCTION(mul
), /* mul */
730 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GEU
), /* cmpgeu */
731 INSTRUCTION_NOP(), /* initi */
732 INSTRUCTION_ILLEGAL(),
733 INSTRUCTION_ILLEGAL(),
734 INSTRUCTION_ILLEGAL(),
735 INSTRUCTION(trap
), /* trap */
736 INSTRUCTION(wrctl
), /* wrctl */
737 INSTRUCTION_ILLEGAL(),
738 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LTU
), /* cmpltu */
739 INSTRUCTION(add
), /* add */
740 INSTRUCTION_ILLEGAL(),
741 INSTRUCTION_ILLEGAL(),
742 INSTRUCTION_FLG(gen_excp
, EXCP_BREAK
), /* break */
743 INSTRUCTION_ILLEGAL(),
744 INSTRUCTION(nop
), /* nop */
745 INSTRUCTION_ILLEGAL(),
746 INSTRUCTION_ILLEGAL(),
747 INSTRUCTION(sub
), /* sub */
748 INSTRUCTION(srai
), /* srai */
749 INSTRUCTION(sra
), /* sra */
750 INSTRUCTION_ILLEGAL(),
751 INSTRUCTION_ILLEGAL(),
752 INSTRUCTION_ILLEGAL(),
753 INSTRUCTION_ILLEGAL(),
756 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
759 const Nios2Instruction
*instr
;
761 opx
= get_opxcode(code
);
762 if (unlikely(opx
>= ARRAY_SIZE(r_type_instructions
))) {
766 instr
= &r_type_instructions
[opx
];
767 instr
->handler(dc
, code
, instr
->flags
);
772 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
775 static const char * const gr_regnames
[NUM_GP_REGS
] = {
776 "zero", "at", "r2", "r3",
777 "r4", "r5", "r6", "r7",
778 "r8", "r9", "r10", "r11",
779 "r12", "r13", "r14", "r15",
780 "r16", "r17", "r18", "r19",
781 "r20", "r21", "r22", "r23",
782 "et", "bt", "gp", "sp",
783 "fp", "ea", "ba", "ra",
786 static const char * const cr_regnames
[NUM_CR_REGS
] = {
787 "status", "estatus", "bstatus", "ienable",
788 "ipending", "cpuid", "reserved0", "exception",
789 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
790 "badaddr", "config", "mpubase", "mpuacc",
791 "reserved2", "reserved3", "reserved4", "reserved5",
792 "reserved6", "reserved7", "reserved8", "reserved9",
793 "reserved10", "reserved11", "reserved12", "reserved13",
794 "reserved14", "reserved15", "reserved16", "reserved17",
797 #include "exec/gen-icount.h"
799 /* generate intermediate code for basic block 'tb'. */
800 static void nios2_tr_init_disas_context(DisasContextBase
*dcbase
, CPUState
*cs
)
802 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
803 CPUNios2State
*env
= cs
->env_ptr
;
806 dc
->mem_idx
= cpu_mmu_index(env
, false);
808 /* Bound the number of insns to execute to those left on the page. */
809 page_insns
= -(dc
->base
.pc_first
| TARGET_PAGE_MASK
) / 4;
810 dc
->base
.max_insns
= MIN(page_insns
, dc
->base
.max_insns
);
813 static void nios2_tr_tb_start(DisasContextBase
*db
, CPUState
*cs
)
817 static void nios2_tr_insn_start(DisasContextBase
*dcbase
, CPUState
*cs
)
819 tcg_gen_insn_start(dcbase
->pc_next
);
822 static void nios2_tr_translate_insn(DisasContextBase
*dcbase
, CPUState
*cs
)
824 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
825 CPUNios2State
*env
= cs
->env_ptr
;
826 const Nios2Instruction
*instr
;
830 pc
= dc
->base
.pc_next
;
832 dc
->base
.pc_next
= pc
+ 4;
834 /* Decode an instruction */
835 code
= cpu_ldl_code(env
, pc
);
836 op
= get_opcode(code
);
838 if (unlikely(op
>= ARRAY_SIZE(i_type_instructions
))) {
839 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
845 instr
= &i_type_instructions
[op
];
846 instr
->handler(dc
, code
, instr
->flags
);
849 tcg_temp_free(dc
->zero
);
853 static void nios2_tr_tb_stop(DisasContextBase
*dcbase
, CPUState
*cs
)
855 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
857 /* Indicate where the next block should start */
858 switch (dc
->base
.is_jmp
) {
861 /* Save the current PC back into the CPU register */
862 tcg_gen_movi_tl(cpu_pc
, dc
->base
.pc_next
);
863 tcg_gen_exit_tb(NULL
, 0);
867 /* The jump will already have updated the PC register */
868 tcg_gen_exit_tb(NULL
, 0);
872 /* nothing more to generate */
876 g_assert_not_reached();
880 static void nios2_tr_disas_log(const DisasContextBase
*dcbase
,
881 CPUState
*cpu
, FILE *logfile
)
883 fprintf(logfile
, "IN: %s\n", lookup_symbol(dcbase
->pc_first
));
884 target_disas(logfile
, cpu
, dcbase
->pc_first
, dcbase
->tb
->size
);
887 static const TranslatorOps nios2_tr_ops
= {
888 .init_disas_context
= nios2_tr_init_disas_context
,
889 .tb_start
= nios2_tr_tb_start
,
890 .insn_start
= nios2_tr_insn_start
,
891 .translate_insn
= nios2_tr_translate_insn
,
892 .tb_stop
= nios2_tr_tb_stop
,
893 .disas_log
= nios2_tr_disas_log
,
896 void gen_intermediate_code(CPUState
*cs
, TranslationBlock
*tb
, int max_insns
)
899 translator_loop(&nios2_tr_ops
, &dc
.base
, cs
, tb
, max_insns
);
902 void nios2_cpu_dump_state(CPUState
*cs
, FILE *f
, int flags
)
904 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
905 CPUNios2State
*env
= &cpu
->env
;
912 qemu_fprintf(f
, "IN: PC=%x %s\n", env
->pc
, lookup_symbol(env
->pc
));
914 for (i
= 0; i
< NUM_GP_REGS
; i
++) {
915 qemu_fprintf(f
, "%9s=%8.8x ", gr_regnames
[i
], env
->regs
[i
]);
916 if ((i
+ 1) % 4 == 0) {
917 qemu_fprintf(f
, "\n");
920 for (i
= 0; i
< NUM_CR_REGS
; i
++) {
921 qemu_fprintf(f
, "%9s=%8.8x ", cr_regnames
[i
], env
->ctrl
[i
]);
922 if ((i
+ 1) % 4 == 0) {
923 qemu_fprintf(f
, "\n");
926 #if !defined(CONFIG_USER_ONLY)
927 qemu_fprintf(f
, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
928 env
->mmu
.pteaddr_wr
& CR_PTEADDR_VPN_MASK
,
929 (env
->mmu
.tlbmisc_wr
& CR_TLBMISC_PID_MASK
) >> 4,
932 qemu_fprintf(f
, "\n\n");
935 void nios2_tcg_init(void)
939 for (i
= 0; i
< NUM_GP_REGS
; i
++) {
940 cpu_R
[i
] = tcg_global_mem_new(cpu_env
,
941 offsetof(CPUNios2State
, regs
[i
]),
944 cpu_pc
= tcg_global_mem_new(cpu_env
,
945 offsetof(CPUNios2State
, pc
), "pc");
948 void restore_state_to_opc(CPUNios2State
*env
, TranslationBlock
*tb
,