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_CORE_REGS
];
108 typedef struct Nios2Instruction
{
109 void (*handler
)(DisasContext
*dc
, uint32_t code
, uint32_t flags
);
113 static uint8_t get_opcode(uint32_t code
)
119 static uint8_t get_opxcode(uint32_t code
)
125 static TCGv
load_zero(DisasContext
*dc
)
128 dc
->zero
= tcg_const_i32(0);
133 static TCGv
load_gpr(DisasContext
*dc
, uint8_t reg
)
135 if (likely(reg
!= R_ZERO
)) {
138 return load_zero(dc
);
142 static void t_gen_helper_raise_exception(DisasContext
*dc
,
145 TCGv_i32 tmp
= tcg_const_i32(index
);
147 tcg_gen_movi_tl(cpu_R
[R_PC
], dc
->pc
);
148 gen_helper_raise_exception(cpu_env
, tmp
);
149 tcg_temp_free_i32(tmp
);
150 dc
->base
.is_jmp
= DISAS_NORETURN
;
153 static void gen_goto_tb(DisasContext
*dc
, int n
, uint32_t dest
)
155 const TranslationBlock
*tb
= dc
->base
.tb
;
157 if (translator_use_goto_tb(&dc
->base
, dest
)) {
159 tcg_gen_movi_tl(cpu_R
[R_PC
], dest
);
160 tcg_gen_exit_tb(tb
, n
);
162 tcg_gen_movi_tl(cpu_R
[R_PC
], dest
);
163 tcg_gen_exit_tb(NULL
, 0);
167 static void gen_excp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
169 t_gen_helper_raise_exception(dc
, flags
);
172 static void gen_check_supervisor(DisasContext
*dc
)
174 if (dc
->base
.tb
->flags
& CR_STATUS_U
) {
175 /* CPU in user mode, privileged instruction called, stop. */
176 t_gen_helper_raise_exception(dc
, EXCP_SUPERI
);
181 * Used as a placeholder for all instructions which do not have
182 * an effect on the simulator (e.g. flush, sync)
184 static void nop(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
186 /* Nothing to do here */
190 * J-Type instructions
192 static void jmpi(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
195 gen_goto_tb(dc
, 0, (dc
->pc
& 0xF0000000) | (instr
.imm26
<< 2));
196 dc
->base
.is_jmp
= DISAS_NORETURN
;
199 static void call(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
201 tcg_gen_movi_tl(cpu_R
[R_RA
], dc
->base
.pc_next
);
202 jmpi(dc
, code
, flags
);
206 * I-Type instructions
208 /* Load instructions */
209 static void gen_ldx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
213 TCGv addr
= tcg_temp_new();
217 * WARNING: Loads into R_ZERO are ignored, but we must generate the
218 * memory access itself to emulate the CPU precisely. Load
219 * from a protected page to R_ZERO will cause SIGSEGV on
222 if (likely(instr
.b
!= R_ZERO
)) {
223 data
= cpu_R
[instr
.b
];
225 data
= tcg_temp_new();
228 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
229 tcg_gen_qemu_ld_tl(data
, addr
, dc
->mem_idx
, flags
);
231 if (unlikely(instr
.b
== R_ZERO
)) {
238 /* Store instructions */
239 static void gen_stx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
242 TCGv val
= load_gpr(dc
, instr
.b
);
244 TCGv addr
= tcg_temp_new();
245 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
246 tcg_gen_qemu_st_tl(val
, addr
, dc
->mem_idx
, flags
);
250 /* Branch instructions */
251 static void br(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
255 gen_goto_tb(dc
, 0, dc
->base
.pc_next
+ (instr
.imm16
.s
& -4));
256 dc
->base
.is_jmp
= DISAS_NORETURN
;
259 static void gen_bxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
263 TCGLabel
*l1
= gen_new_label();
264 tcg_gen_brcond_tl(flags
, cpu_R
[instr
.a
], cpu_R
[instr
.b
], l1
);
265 gen_goto_tb(dc
, 0, dc
->base
.pc_next
);
267 gen_goto_tb(dc
, 1, dc
->base
.pc_next
+ (instr
.imm16
.s
& -4));
268 dc
->base
.is_jmp
= DISAS_NORETURN
;
271 /* Comparison instructions */
272 #define gen_i_cmpxx(fname, op3) \
273 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
275 I_TYPE(instr, (code)); \
276 tcg_gen_setcondi_tl(flags, cpu_R[instr.b], cpu_R[instr.a], (op3)); \
279 gen_i_cmpxx(gen_cmpxxsi
, instr
.imm16
.s
)
280 gen_i_cmpxx(gen_cmpxxui
, instr
.imm16
.u
)
282 /* Math/logic instructions */
283 #define gen_i_math_logic(fname, insn, resimm, op3) \
284 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
286 I_TYPE(instr, (code)); \
287 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
289 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
290 tcg_gen_movi_tl(cpu_R[instr.b], (resimm) ? (op3) : 0); \
292 tcg_gen_##insn##_tl(cpu_R[instr.b], cpu_R[instr.a], (op3)); \
296 gen_i_math_logic(addi
, addi
, 1, instr
.imm16
.s
)
297 gen_i_math_logic(muli
, muli
, 0, instr
.imm16
.s
)
299 gen_i_math_logic(andi
, andi
, 0, instr
.imm16
.u
)
300 gen_i_math_logic(ori
, ori
, 1, instr
.imm16
.u
)
301 gen_i_math_logic(xori
, xori
, 1, instr
.imm16
.u
)
303 gen_i_math_logic(andhi
, andi
, 0, instr
.imm16
.u
<< 16)
304 gen_i_math_logic(orhi
, ori
, 1, instr
.imm16
.u
<< 16)
305 gen_i_math_logic(xorhi
, xori
, 1, instr
.imm16
.u
<< 16)
307 /* Prototype only, defined below */
308 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
,
311 static const Nios2Instruction i_type_instructions
[] = {
312 INSTRUCTION(call
), /* call */
313 INSTRUCTION(jmpi
), /* jmpi */
314 INSTRUCTION_ILLEGAL(),
315 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbu */
316 INSTRUCTION(addi
), /* addi */
317 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stb */
318 INSTRUCTION(br
), /* br */
319 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldb */
320 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_GE
), /* cmpgei */
321 INSTRUCTION_ILLEGAL(),
322 INSTRUCTION_ILLEGAL(),
323 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhu */
324 INSTRUCTION(andi
), /* andi */
325 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sth */
326 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GE
), /* bge */
327 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldh */
328 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_LT
), /* cmplti */
329 INSTRUCTION_ILLEGAL(),
330 INSTRUCTION_ILLEGAL(),
331 INSTRUCTION_NOP(), /* initda */
332 INSTRUCTION(ori
), /* ori */
333 INSTRUCTION_FLG(gen_stx
, MO_UL
), /* stw */
334 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LT
), /* blt */
335 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldw */
336 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_NE
), /* cmpnei */
337 INSTRUCTION_ILLEGAL(),
338 INSTRUCTION_ILLEGAL(),
339 INSTRUCTION_NOP(), /* flushda */
340 INSTRUCTION(xori
), /* xori */
341 INSTRUCTION_ILLEGAL(),
342 INSTRUCTION_FLG(gen_bxx
, TCG_COND_NE
), /* bne */
343 INSTRUCTION_ILLEGAL(),
344 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_EQ
), /* cmpeqi */
345 INSTRUCTION_ILLEGAL(),
346 INSTRUCTION_ILLEGAL(),
347 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbuio */
348 INSTRUCTION(muli
), /* muli */
349 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stbio */
350 INSTRUCTION_FLG(gen_bxx
, TCG_COND_EQ
), /* beq */
351 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldbio */
352 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_GEU
), /* cmpgeui */
353 INSTRUCTION_ILLEGAL(),
354 INSTRUCTION_ILLEGAL(),
355 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhuio */
356 INSTRUCTION(andhi
), /* andhi */
357 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sthio */
358 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GEU
), /* bgeu */
359 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldhio */
360 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_LTU
), /* cmpltui */
361 INSTRUCTION_ILLEGAL(),
362 INSTRUCTION_UNIMPLEMENTED(), /* custom */
363 INSTRUCTION_NOP(), /* initd */
364 INSTRUCTION(orhi
), /* orhi */
365 INSTRUCTION_FLG(gen_stx
, MO_SL
), /* stwio */
366 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LTU
), /* bltu */
367 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldwio */
368 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
369 INSTRUCTION_ILLEGAL(),
370 INSTRUCTION_FLG(handle_r_type_instr
, 0), /* R-Type */
371 INSTRUCTION_NOP(), /* flushd */
372 INSTRUCTION(xorhi
), /* xorhi */
373 INSTRUCTION_ILLEGAL(),
374 INSTRUCTION_ILLEGAL(),
375 INSTRUCTION_ILLEGAL(),
379 * R-Type instructions
385 static void eret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
387 tcg_gen_mov_tl(cpu_R
[CR_STATUS
], cpu_R
[CR_ESTATUS
]);
388 tcg_gen_mov_tl(cpu_R
[R_PC
], cpu_R
[R_EA
]);
390 dc
->base
.is_jmp
= DISAS_JUMP
;
394 static void ret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
396 tcg_gen_mov_tl(cpu_R
[R_PC
], cpu_R
[R_RA
]);
398 dc
->base
.is_jmp
= DISAS_JUMP
;
402 static void bret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
404 tcg_gen_mov_tl(cpu_R
[R_PC
], cpu_R
[R_BA
]);
406 dc
->base
.is_jmp
= DISAS_JUMP
;
410 static void jmp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
414 tcg_gen_mov_tl(cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
416 dc
->base
.is_jmp
= DISAS_JUMP
;
420 static void nextpc(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
424 if (likely(instr
.c
!= R_ZERO
)) {
425 tcg_gen_movi_tl(cpu_R
[instr
.c
], dc
->base
.pc_next
);
433 static void callr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
437 tcg_gen_mov_tl(cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
438 tcg_gen_movi_tl(cpu_R
[R_RA
], dc
->base
.pc_next
);
440 dc
->base
.is_jmp
= DISAS_JUMP
;
444 static void rdctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
448 gen_check_supervisor(dc
);
450 switch (instr
.imm5
+ CR_BASE
) {
455 #if !defined(CONFIG_USER_ONLY)
456 if (likely(instr
.c
!= R_ZERO
)) {
457 tcg_gen_mov_tl(cpu_R
[instr
.c
], cpu_R
[instr
.imm5
+ CR_BASE
]);
459 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
460 gen_helper_mmu_read_debug(cpu_R
[instr
.c
], cpu_env
, tmp
);
461 tcg_temp_free_i32(tmp
);
469 if (likely(instr
.c
!= R_ZERO
)) {
470 tcg_gen_mov_tl(cpu_R
[instr
.c
], cpu_R
[instr
.imm5
+ CR_BASE
]);
477 static void wrctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
481 gen_check_supervisor(dc
);
483 switch (instr
.imm5
+ CR_BASE
) {
488 #if !defined(CONFIG_USER_ONLY)
489 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
490 gen_helper_mmu_write(cpu_env
, tmp
, load_gpr(dc
, instr
.a
));
491 tcg_temp_free_i32(tmp
);
497 tcg_gen_mov_tl(cpu_R
[instr
.imm5
+ CR_BASE
], load_gpr(dc
, instr
.a
));
501 /* If interrupts were enabled using WRCTL, trigger them. */
502 #if !defined(CONFIG_USER_ONLY)
503 if ((instr
.imm5
+ CR_BASE
) == CR_STATUS
) {
504 if (tb_cflags(dc
->base
.tb
) & CF_USE_ICOUNT
) {
507 gen_helper_check_interrupts(cpu_env
);
508 dc
->base
.is_jmp
= DISAS_UPDATE
;
513 /* Comparison instructions */
514 static void gen_cmpxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
517 if (likely(instr
.c
!= R_ZERO
)) {
518 tcg_gen_setcond_tl(flags
, cpu_R
[instr
.c
], cpu_R
[instr
.a
],
523 /* Math/logic instructions */
524 #define gen_r_math_logic(fname, insn, op3) \
525 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
527 R_TYPE(instr, (code)); \
528 if (likely(instr.c != R_ZERO)) { \
529 tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), (op3)); \
533 gen_r_math_logic(add
, add_tl
, load_gpr(dc
, instr
.b
))
534 gen_r_math_logic(sub
, sub_tl
, load_gpr(dc
, instr
.b
))
535 gen_r_math_logic(mul
, mul_tl
, load_gpr(dc
, instr
.b
))
537 gen_r_math_logic(and, and_tl
, load_gpr(dc
, instr
.b
))
538 gen_r_math_logic(or, or_tl
, load_gpr(dc
, instr
.b
))
539 gen_r_math_logic(xor, xor_tl
, load_gpr(dc
, instr
.b
))
540 gen_r_math_logic(nor
, nor_tl
, load_gpr(dc
, instr
.b
))
542 gen_r_math_logic(srai
, sari_tl
, instr
.imm5
)
543 gen_r_math_logic(srli
, shri_tl
, instr
.imm5
)
544 gen_r_math_logic(slli
, shli_tl
, instr
.imm5
)
545 gen_r_math_logic(roli
, rotli_tl
, instr
.imm5
)
547 #define gen_r_mul(fname, insn) \
548 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
550 R_TYPE(instr, (code)); \
551 if (likely(instr.c != R_ZERO)) { \
552 TCGv t0 = tcg_temp_new(); \
553 tcg_gen_##insn(t0, cpu_R[instr.c], \
554 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
559 gen_r_mul(mulxss
, muls2_tl
)
560 gen_r_mul(mulxuu
, mulu2_tl
)
561 gen_r_mul(mulxsu
, mulsu2_tl
)
563 #define gen_r_shift_s(fname, insn) \
564 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
566 R_TYPE(instr, (code)); \
567 if (likely(instr.c != R_ZERO)) { \
568 TCGv t0 = tcg_temp_new(); \
569 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
570 tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
575 gen_r_shift_s(sra
, sar_tl
)
576 gen_r_shift_s(srl
, shr_tl
)
577 gen_r_shift_s(sll
, shl_tl
)
578 gen_r_shift_s(rol
, rotl_tl
)
579 gen_r_shift_s(ror
, rotr_tl
)
581 static void divs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
583 R_TYPE(instr
, (code
));
585 /* Stores into R_ZERO are ignored */
586 if (unlikely(instr
.c
== R_ZERO
)) {
590 TCGv t0
= tcg_temp_new();
591 TCGv t1
= tcg_temp_new();
592 TCGv t2
= tcg_temp_new();
593 TCGv t3
= tcg_temp_new();
595 tcg_gen_ext32s_tl(t0
, load_gpr(dc
, instr
.a
));
596 tcg_gen_ext32s_tl(t1
, load_gpr(dc
, instr
.b
));
597 tcg_gen_setcondi_tl(TCG_COND_EQ
, t2
, t0
, INT_MIN
);
598 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, -1);
599 tcg_gen_and_tl(t2
, t2
, t3
);
600 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, 0);
601 tcg_gen_or_tl(t2
, t2
, t3
);
602 tcg_gen_movi_tl(t3
, 0);
603 tcg_gen_movcond_tl(TCG_COND_NE
, t1
, t2
, t3
, t2
, t1
);
604 tcg_gen_div_tl(cpu_R
[instr
.c
], t0
, t1
);
605 tcg_gen_ext32s_tl(cpu_R
[instr
.c
], cpu_R
[instr
.c
]);
613 static void divu(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
615 R_TYPE(instr
, (code
));
617 /* Stores into R_ZERO are ignored */
618 if (unlikely(instr
.c
== R_ZERO
)) {
622 TCGv t0
= tcg_temp_new();
623 TCGv t1
= tcg_temp_new();
624 TCGv t2
= tcg_const_tl(0);
625 TCGv t3
= tcg_const_tl(1);
627 tcg_gen_ext32u_tl(t0
, load_gpr(dc
, instr
.a
));
628 tcg_gen_ext32u_tl(t1
, load_gpr(dc
, instr
.b
));
629 tcg_gen_movcond_tl(TCG_COND_EQ
, t1
, t1
, t2
, t3
, t1
);
630 tcg_gen_divu_tl(cpu_R
[instr
.c
], t0
, t1
);
631 tcg_gen_ext32s_tl(cpu_R
[instr
.c
], cpu_R
[instr
.c
]);
639 static void trap(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
641 #ifdef CONFIG_USER_ONLY
643 * The imm5 field is not stored anywhere on real hw; the kernel
644 * has to load the insn and extract the field. But we can make
645 * things easier for cpu_loop if we pop this into env->error_code.
648 tcg_gen_st_i32(tcg_constant_i32(instr
.imm5
), cpu_env
,
649 offsetof(CPUNios2State
, error_code
));
651 t_gen_helper_raise_exception(dc
, EXCP_TRAP
);
654 static const Nios2Instruction r_type_instructions
[] = {
655 INSTRUCTION_ILLEGAL(),
656 INSTRUCTION(eret
), /* eret */
657 INSTRUCTION(roli
), /* roli */
658 INSTRUCTION(rol
), /* rol */
659 INSTRUCTION_NOP(), /* flushp */
660 INSTRUCTION(ret
), /* ret */
661 INSTRUCTION(nor
), /* nor */
662 INSTRUCTION(mulxuu
), /* mulxuu */
663 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GE
), /* cmpge */
664 INSTRUCTION(bret
), /* bret */
665 INSTRUCTION_ILLEGAL(),
666 INSTRUCTION(ror
), /* ror */
667 INSTRUCTION_NOP(), /* flushi */
668 INSTRUCTION(jmp
), /* jmp */
669 INSTRUCTION(and), /* and */
670 INSTRUCTION_ILLEGAL(),
671 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LT
), /* cmplt */
672 INSTRUCTION_ILLEGAL(),
673 INSTRUCTION(slli
), /* slli */
674 INSTRUCTION(sll
), /* sll */
675 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
676 INSTRUCTION_ILLEGAL(),
677 INSTRUCTION(or), /* or */
678 INSTRUCTION(mulxsu
), /* mulxsu */
679 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_NE
), /* cmpne */
680 INSTRUCTION_ILLEGAL(),
681 INSTRUCTION(srli
), /* srli */
682 INSTRUCTION(srl
), /* srl */
683 INSTRUCTION(nextpc
), /* nextpc */
684 INSTRUCTION(callr
), /* callr */
685 INSTRUCTION(xor), /* xor */
686 INSTRUCTION(mulxss
), /* mulxss */
687 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_EQ
), /* cmpeq */
688 INSTRUCTION_ILLEGAL(),
689 INSTRUCTION_ILLEGAL(),
690 INSTRUCTION_ILLEGAL(),
691 INSTRUCTION(divu
), /* divu */
692 INSTRUCTION(divs
), /* div */
693 INSTRUCTION(rdctl
), /* rdctl */
694 INSTRUCTION(mul
), /* mul */
695 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GEU
), /* cmpgeu */
696 INSTRUCTION_NOP(), /* initi */
697 INSTRUCTION_ILLEGAL(),
698 INSTRUCTION_ILLEGAL(),
699 INSTRUCTION_ILLEGAL(),
700 INSTRUCTION(trap
), /* trap */
701 INSTRUCTION(wrctl
), /* wrctl */
702 INSTRUCTION_ILLEGAL(),
703 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LTU
), /* cmpltu */
704 INSTRUCTION(add
), /* add */
705 INSTRUCTION_ILLEGAL(),
706 INSTRUCTION_ILLEGAL(),
707 INSTRUCTION_FLG(gen_excp
, EXCP_BREAK
), /* break */
708 INSTRUCTION_ILLEGAL(),
709 INSTRUCTION(nop
), /* nop */
710 INSTRUCTION_ILLEGAL(),
711 INSTRUCTION_ILLEGAL(),
712 INSTRUCTION(sub
), /* sub */
713 INSTRUCTION(srai
), /* srai */
714 INSTRUCTION(sra
), /* sra */
715 INSTRUCTION_ILLEGAL(),
716 INSTRUCTION_ILLEGAL(),
717 INSTRUCTION_ILLEGAL(),
718 INSTRUCTION_ILLEGAL(),
721 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
724 const Nios2Instruction
*instr
;
726 opx
= get_opxcode(code
);
727 if (unlikely(opx
>= ARRAY_SIZE(r_type_instructions
))) {
731 instr
= &r_type_instructions
[opx
];
732 instr
->handler(dc
, code
, instr
->flags
);
737 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
740 static const char * const regnames
[] = {
741 "zero", "at", "r2", "r3",
742 "r4", "r5", "r6", "r7",
743 "r8", "r9", "r10", "r11",
744 "r12", "r13", "r14", "r15",
745 "r16", "r17", "r18", "r19",
746 "r20", "r21", "r22", "r23",
747 "et", "bt", "gp", "sp",
748 "fp", "ea", "ba", "ra",
749 "status", "estatus", "bstatus", "ienable",
750 "ipending", "cpuid", "reserved0", "exception",
751 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
752 "badaddr", "config", "mpubase", "mpuacc",
753 "reserved2", "reserved3", "reserved4", "reserved5",
754 "reserved6", "reserved7", "reserved8", "reserved9",
755 "reserved10", "reserved11", "reserved12", "reserved13",
756 "reserved14", "reserved15", "reserved16", "reserved17",
760 #include "exec/gen-icount.h"
762 /* generate intermediate code for basic block 'tb'. */
763 static void nios2_tr_init_disas_context(DisasContextBase
*dcbase
, CPUState
*cs
)
765 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
766 CPUNios2State
*env
= cs
->env_ptr
;
769 dc
->mem_idx
= cpu_mmu_index(env
, false);
771 /* Bound the number of insns to execute to those left on the page. */
772 page_insns
= -(dc
->base
.pc_first
| TARGET_PAGE_MASK
) / 4;
773 dc
->base
.max_insns
= MIN(page_insns
, dc
->base
.max_insns
);
776 static void nios2_tr_tb_start(DisasContextBase
*db
, CPUState
*cs
)
780 static void nios2_tr_insn_start(DisasContextBase
*dcbase
, CPUState
*cs
)
782 tcg_gen_insn_start(dcbase
->pc_next
);
785 static void nios2_tr_translate_insn(DisasContextBase
*dcbase
, CPUState
*cs
)
787 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
788 CPUNios2State
*env
= cs
->env_ptr
;
789 const Nios2Instruction
*instr
;
793 pc
= dc
->base
.pc_next
;
795 dc
->base
.pc_next
= pc
+ 4;
797 /* Decode an instruction */
798 code
= cpu_ldl_code(env
, pc
);
799 op
= get_opcode(code
);
801 if (unlikely(op
>= ARRAY_SIZE(i_type_instructions
))) {
802 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
808 instr
= &i_type_instructions
[op
];
809 instr
->handler(dc
, code
, instr
->flags
);
812 tcg_temp_free(dc
->zero
);
816 static void nios2_tr_tb_stop(DisasContextBase
*dcbase
, CPUState
*cs
)
818 DisasContext
*dc
= container_of(dcbase
, DisasContext
, base
);
820 /* Indicate where the next block should start */
821 switch (dc
->base
.is_jmp
) {
824 /* Save the current PC back into the CPU register */
825 tcg_gen_movi_tl(cpu_R
[R_PC
], dc
->base
.pc_next
);
826 tcg_gen_exit_tb(NULL
, 0);
830 /* The jump will already have updated the PC register */
831 tcg_gen_exit_tb(NULL
, 0);
835 /* nothing more to generate */
839 g_assert_not_reached();
843 static void nios2_tr_disas_log(const DisasContextBase
*dcbase
, CPUState
*cpu
)
845 qemu_log("IN: %s\n", lookup_symbol(dcbase
->pc_first
));
846 log_target_disas(cpu
, dcbase
->pc_first
, dcbase
->tb
->size
);
849 static const TranslatorOps nios2_tr_ops
= {
850 .init_disas_context
= nios2_tr_init_disas_context
,
851 .tb_start
= nios2_tr_tb_start
,
852 .insn_start
= nios2_tr_insn_start
,
853 .translate_insn
= nios2_tr_translate_insn
,
854 .tb_stop
= nios2_tr_tb_stop
,
855 .disas_log
= nios2_tr_disas_log
,
858 void gen_intermediate_code(CPUState
*cs
, TranslationBlock
*tb
, int max_insns
)
861 translator_loop(&nios2_tr_ops
, &dc
.base
, cs
, tb
, max_insns
);
864 void nios2_cpu_dump_state(CPUState
*cs
, FILE *f
, int flags
)
866 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
867 CPUNios2State
*env
= &cpu
->env
;
874 qemu_fprintf(f
, "IN: PC=%x %s\n",
875 env
->regs
[R_PC
], lookup_symbol(env
->regs
[R_PC
]));
877 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
878 qemu_fprintf(f
, "%9s=%8.8x ", regnames
[i
], env
->regs
[i
]);
879 if ((i
+ 1) % 4 == 0) {
880 qemu_fprintf(f
, "\n");
883 #if !defined(CONFIG_USER_ONLY)
884 qemu_fprintf(f
, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
885 env
->mmu
.pteaddr_wr
& CR_PTEADDR_VPN_MASK
,
886 (env
->mmu
.tlbmisc_wr
& CR_TLBMISC_PID_MASK
) >> 4,
889 qemu_fprintf(f
, "\n\n");
892 void nios2_tcg_init(void)
896 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
897 cpu_R
[i
] = tcg_global_mem_new(cpu_env
,
898 offsetof(CPUNios2State
, regs
[i
]),
903 void restore_state_to_opc(CPUNios2State
*env
, TranslationBlock
*tb
,
906 env
->regs
[R_PC
] = data
[0];