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>
26 #include "exec/exec-all.h"
27 #include "disas/disas.h"
28 #include "exec/helper-proto.h"
29 #include "exec/helper-gen.h"
31 #include "exec/cpu_ldst.h"
32 #include "exec/translator.h"
34 /* is_jmp field values */
35 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
36 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
37 #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
39 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
40 #define INSTRUCTION(func) \
41 INSTRUCTION_FLG(func, 0)
42 #define INSTRUCTION_NOP() \
43 INSTRUCTION_FLG(nop, 0)
44 #define INSTRUCTION_UNIMPLEMENTED() \
45 INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
46 #define INSTRUCTION_ILLEGAL() \
47 INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
49 /* Special R-Type instruction opcode */
50 #define INSN_R_TYPE 0x3A
52 /* I-Type instruction parsing */
53 #define I_TYPE(instr, code) \
63 .op = extract32((code), 0, 6), \
64 .imm16.u = extract32((code), 6, 16), \
65 .b = extract32((code), 22, 5), \
66 .a = extract32((code), 27, 5), \
69 /* R-Type instruction parsing */
70 #define R_TYPE(instr, code) \
79 .op = extract32((code), 0, 6), \
80 .imm5 = extract32((code), 6, 5), \
81 .opx = extract32((code), 11, 6), \
82 .c = extract32((code), 17, 5), \
83 .b = extract32((code), 22, 5), \
84 .a = extract32((code), 27, 5), \
87 /* J-Type instruction parsing */
88 #define J_TYPE(instr, code) \
93 .op = extract32((code), 0, 6), \
94 .imm26 = extract32((code), 6, 26), \
97 typedef struct DisasContext
{
103 TranslationBlock
*tb
;
105 bool singlestep_enabled
;
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
)
127 if (TCGV_IS_UNUSED_I32(dc
->zero
)) {
128 dc
->zero
= tcg_const_i32(0);
133 static TCGv
load_gpr(DisasContext
*dc
, uint8_t reg
)
135 if (likely(reg
!= R_ZERO
)) {
136 return dc
->cpu_R
[reg
];
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(dc
->cpu_R
[R_PC
], dc
->pc
);
148 gen_helper_raise_exception(dc
->cpu_env
, tmp
);
149 tcg_temp_free_i32(tmp
);
150 dc
->is_jmp
= DISAS_UPDATE
;
153 static bool use_goto_tb(DisasContext
*dc
, uint32_t dest
)
155 if (unlikely(dc
->singlestep_enabled
)) {
159 #ifndef CONFIG_USER_ONLY
160 return (dc
->tb
->pc
& TARGET_PAGE_MASK
) == (dest
& TARGET_PAGE_MASK
);
166 static void gen_goto_tb(DisasContext
*dc
, int n
, uint32_t dest
)
168 TranslationBlock
*tb
= dc
->tb
;
170 if (use_goto_tb(dc
, dest
)) {
172 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dest
);
173 tcg_gen_exit_tb((uintptr_t)tb
+ n
);
175 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dest
);
180 static void gen_excp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
182 t_gen_helper_raise_exception(dc
, flags
);
185 static void gen_check_supervisor(DisasContext
*dc
)
187 if (dc
->tb
->flags
& CR_STATUS_U
) {
188 /* CPU in user mode, privileged instruction called, stop. */
189 t_gen_helper_raise_exception(dc
, EXCP_SUPERI
);
194 * Used as a placeholder for all instructions which do not have
195 * an effect on the simulator (e.g. flush, sync)
197 static void nop(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
199 /* Nothing to do here */
203 * J-Type instructions
205 static void jmpi(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
208 gen_goto_tb(dc
, 0, (dc
->pc
& 0xF0000000) | (instr
.imm26
<< 2));
209 dc
->is_jmp
= DISAS_TB_JUMP
;
212 static void call(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
214 tcg_gen_movi_tl(dc
->cpu_R
[R_RA
], dc
->pc
+ 4);
215 jmpi(dc
, code
, flags
);
219 * I-Type instructions
221 /* Load instructions */
222 static void gen_ldx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
226 TCGv addr
= tcg_temp_new();
230 * WARNING: Loads into R_ZERO are ignored, but we must generate the
231 * memory access itself to emulate the CPU precisely. Load
232 * from a protected page to R_ZERO will cause SIGSEGV on
235 if (likely(instr
.b
!= R_ZERO
)) {
236 data
= dc
->cpu_R
[instr
.b
];
238 data
= tcg_temp_new();
241 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
242 tcg_gen_qemu_ld_tl(data
, addr
, dc
->mem_idx
, flags
);
244 if (unlikely(instr
.b
== R_ZERO
)) {
251 /* Store instructions */
252 static void gen_stx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
255 TCGv val
= load_gpr(dc
, instr
.b
);
257 TCGv addr
= tcg_temp_new();
258 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
259 tcg_gen_qemu_st_tl(val
, addr
, dc
->mem_idx
, flags
);
263 /* Branch instructions */
264 static void br(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
268 gen_goto_tb(dc
, 0, dc
->pc
+ 4 + (instr
.imm16
.s
& -4));
269 dc
->is_jmp
= DISAS_TB_JUMP
;
272 static void gen_bxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
276 TCGLabel
*l1
= gen_new_label();
277 tcg_gen_brcond_tl(flags
, dc
->cpu_R
[instr
.a
], dc
->cpu_R
[instr
.b
], l1
);
278 gen_goto_tb(dc
, 0, dc
->pc
+ 4);
280 gen_goto_tb(dc
, 1, dc
->pc
+ 4 + (instr
.imm16
.s
& -4));
281 dc
->is_jmp
= DISAS_TB_JUMP
;
284 /* Comparison instructions */
285 #define gen_i_cmpxx(fname, op3) \
286 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
288 I_TYPE(instr, (code)); \
289 tcg_gen_setcondi_tl(flags, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
293 gen_i_cmpxx(gen_cmpxxsi
, instr
.imm16
.s
)
294 gen_i_cmpxx(gen_cmpxxui
, instr
.imm16
.u
)
296 /* Math/logic instructions */
297 #define gen_i_math_logic(fname, insn, resimm, op3) \
298 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
300 I_TYPE(instr, (code)); \
301 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
303 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
304 tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0); \
306 tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
311 gen_i_math_logic(addi
, addi
, 1, instr
.imm16
.s
)
312 gen_i_math_logic(muli
, muli
, 0, instr
.imm16
.s
)
314 gen_i_math_logic(andi
, andi
, 0, instr
.imm16
.u
)
315 gen_i_math_logic(ori
, ori
, 1, instr
.imm16
.u
)
316 gen_i_math_logic(xori
, xori
, 1, instr
.imm16
.u
)
318 gen_i_math_logic(andhi
, andi
, 0, instr
.imm16
.u
<< 16)
319 gen_i_math_logic(orhi
, ori
, 1, instr
.imm16
.u
<< 16)
320 gen_i_math_logic(xorhi
, xori
, 1, instr
.imm16
.u
<< 16)
322 /* Prototype only, defined below */
323 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
,
326 static const Nios2Instruction i_type_instructions
[] = {
327 INSTRUCTION(call
), /* call */
328 INSTRUCTION(jmpi
), /* jmpi */
329 INSTRUCTION_ILLEGAL(),
330 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbu */
331 INSTRUCTION(addi
), /* addi */
332 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stb */
333 INSTRUCTION(br
), /* br */
334 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldb */
335 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_GE
), /* cmpgei */
336 INSTRUCTION_ILLEGAL(),
337 INSTRUCTION_ILLEGAL(),
338 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhu */
339 INSTRUCTION(andi
), /* andi */
340 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sth */
341 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GE
), /* bge */
342 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldh */
343 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_LT
), /* cmplti */
344 INSTRUCTION_ILLEGAL(),
345 INSTRUCTION_ILLEGAL(),
346 INSTRUCTION_NOP(), /* initda */
347 INSTRUCTION(ori
), /* ori */
348 INSTRUCTION_FLG(gen_stx
, MO_UL
), /* stw */
349 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LT
), /* blt */
350 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldw */
351 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_NE
), /* cmpnei */
352 INSTRUCTION_ILLEGAL(),
353 INSTRUCTION_ILLEGAL(),
354 INSTRUCTION_NOP(), /* flushda */
355 INSTRUCTION(xori
), /* xori */
356 INSTRUCTION_ILLEGAL(),
357 INSTRUCTION_FLG(gen_bxx
, TCG_COND_NE
), /* bne */
358 INSTRUCTION_ILLEGAL(),
359 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_EQ
), /* cmpeqi */
360 INSTRUCTION_ILLEGAL(),
361 INSTRUCTION_ILLEGAL(),
362 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbuio */
363 INSTRUCTION(muli
), /* muli */
364 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stbio */
365 INSTRUCTION_FLG(gen_bxx
, TCG_COND_EQ
), /* beq */
366 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldbio */
367 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_GEU
), /* cmpgeui */
368 INSTRUCTION_ILLEGAL(),
369 INSTRUCTION_ILLEGAL(),
370 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhuio */
371 INSTRUCTION(andhi
), /* andhi */
372 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sthio */
373 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GEU
), /* bgeu */
374 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldhio */
375 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_LTU
), /* cmpltui */
376 INSTRUCTION_ILLEGAL(),
377 INSTRUCTION_UNIMPLEMENTED(), /* custom */
378 INSTRUCTION_NOP(), /* initd */
379 INSTRUCTION(orhi
), /* orhi */
380 INSTRUCTION_FLG(gen_stx
, MO_SL
), /* stwio */
381 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LTU
), /* bltu */
382 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldwio */
383 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
384 INSTRUCTION_ILLEGAL(),
385 INSTRUCTION_FLG(handle_r_type_instr
, 0), /* R-Type */
386 INSTRUCTION_NOP(), /* flushd */
387 INSTRUCTION(xorhi
), /* xorhi */
388 INSTRUCTION_ILLEGAL(),
389 INSTRUCTION_ILLEGAL(),
390 INSTRUCTION_ILLEGAL(),
394 * R-Type instructions
400 static void eret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
402 tcg_gen_mov_tl(dc
->cpu_R
[CR_STATUS
], dc
->cpu_R
[CR_ESTATUS
]);
403 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_EA
]);
405 dc
->is_jmp
= DISAS_JUMP
;
409 static void ret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
411 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_RA
]);
413 dc
->is_jmp
= DISAS_JUMP
;
417 static void bret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
419 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_BA
]);
421 dc
->is_jmp
= DISAS_JUMP
;
425 static void jmp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
429 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
431 dc
->is_jmp
= DISAS_JUMP
;
435 static void nextpc(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
439 if (likely(instr
.c
!= R_ZERO
)) {
440 tcg_gen_movi_tl(dc
->cpu_R
[instr
.c
], dc
->pc
+ 4);
448 static void callr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
452 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
453 tcg_gen_movi_tl(dc
->cpu_R
[R_RA
], dc
->pc
+ 4);
455 dc
->is_jmp
= DISAS_JUMP
;
459 static void rdctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
463 gen_check_supervisor(dc
);
465 switch (instr
.imm5
+ CR_BASE
) {
470 #if !defined(CONFIG_USER_ONLY)
471 if (likely(instr
.c
!= R_ZERO
)) {
472 tcg_gen_mov_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.imm5
+ CR_BASE
]);
474 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
475 gen_helper_mmu_read_debug(dc
->cpu_R
[instr
.c
], dc
->cpu_env
, tmp
);
476 tcg_temp_free_i32(tmp
);
484 if (likely(instr
.c
!= R_ZERO
)) {
485 tcg_gen_mov_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.imm5
+ CR_BASE
]);
492 static void wrctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
496 gen_check_supervisor(dc
);
498 switch (instr
.imm5
+ CR_BASE
) {
503 #if !defined(CONFIG_USER_ONLY)
504 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
505 gen_helper_mmu_write(dc
->cpu_env
, tmp
, load_gpr(dc
, instr
.a
));
506 tcg_temp_free_i32(tmp
);
512 tcg_gen_mov_tl(dc
->cpu_R
[instr
.imm5
+ CR_BASE
], load_gpr(dc
, instr
.a
));
516 /* If interrupts were enabled using WRCTL, trigger them. */
517 #if !defined(CONFIG_USER_ONLY)
518 if ((instr
.imm5
+ CR_BASE
) == CR_STATUS
) {
519 gen_helper_check_interrupts(dc
->cpu_env
);
524 /* Comparison instructions */
525 static void gen_cmpxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
528 if (likely(instr
.c
!= R_ZERO
)) {
529 tcg_gen_setcond_tl(flags
, dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.a
],
534 /* Math/logic instructions */
535 #define gen_r_math_logic(fname, insn, op3) \
536 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
538 R_TYPE(instr, (code)); \
539 if (likely(instr.c != R_ZERO)) { \
540 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), \
545 gen_r_math_logic(add
, add_tl
, load_gpr(dc
, instr
.b
))
546 gen_r_math_logic(sub
, sub_tl
, load_gpr(dc
, instr
.b
))
547 gen_r_math_logic(mul
, mul_tl
, load_gpr(dc
, instr
.b
))
549 gen_r_math_logic(and, and_tl
, load_gpr(dc
, instr
.b
))
550 gen_r_math_logic(or, or_tl
, load_gpr(dc
, instr
.b
))
551 gen_r_math_logic(xor, xor_tl
, load_gpr(dc
, instr
.b
))
552 gen_r_math_logic(nor
, nor_tl
, load_gpr(dc
, instr
.b
))
554 gen_r_math_logic(srai
, sari_tl
, instr
.imm5
)
555 gen_r_math_logic(srli
, shri_tl
, instr
.imm5
)
556 gen_r_math_logic(slli
, shli_tl
, instr
.imm5
)
557 gen_r_math_logic(roli
, rotli_tl
, instr
.imm5
)
559 #define gen_r_mul(fname, insn) \
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 TCGv t0 = tcg_temp_new(); \
565 tcg_gen_##insn(t0, dc->cpu_R[instr.c], \
566 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
571 gen_r_mul(mulxss
, muls2_tl
)
572 gen_r_mul(mulxuu
, mulu2_tl
)
573 gen_r_mul(mulxsu
, mulsu2_tl
)
575 #define gen_r_shift_s(fname, insn) \
576 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
578 R_TYPE(instr, (code)); \
579 if (likely(instr.c != R_ZERO)) { \
580 TCGv t0 = tcg_temp_new(); \
581 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
582 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
587 gen_r_shift_s(sra
, sar_tl
)
588 gen_r_shift_s(srl
, shr_tl
)
589 gen_r_shift_s(sll
, shl_tl
)
590 gen_r_shift_s(rol
, rotl_tl
)
591 gen_r_shift_s(ror
, rotr_tl
)
593 static void divs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
595 R_TYPE(instr
, (code
));
597 /* Stores into R_ZERO are ignored */
598 if (unlikely(instr
.c
== R_ZERO
)) {
602 TCGv t0
= tcg_temp_new();
603 TCGv t1
= tcg_temp_new();
604 TCGv t2
= tcg_temp_new();
605 TCGv t3
= tcg_temp_new();
607 tcg_gen_ext32s_tl(t0
, load_gpr(dc
, instr
.a
));
608 tcg_gen_ext32s_tl(t1
, load_gpr(dc
, instr
.b
));
609 tcg_gen_setcondi_tl(TCG_COND_EQ
, t2
, t0
, INT_MIN
);
610 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, -1);
611 tcg_gen_and_tl(t2
, t2
, t3
);
612 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, 0);
613 tcg_gen_or_tl(t2
, t2
, t3
);
614 tcg_gen_movi_tl(t3
, 0);
615 tcg_gen_movcond_tl(TCG_COND_NE
, t1
, t2
, t3
, t2
, t1
);
616 tcg_gen_div_tl(dc
->cpu_R
[instr
.c
], t0
, t1
);
617 tcg_gen_ext32s_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.c
]);
625 static void divu(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
627 R_TYPE(instr
, (code
));
629 /* Stores into R_ZERO are ignored */
630 if (unlikely(instr
.c
== R_ZERO
)) {
634 TCGv t0
= tcg_temp_new();
635 TCGv t1
= tcg_temp_new();
636 TCGv t2
= tcg_const_tl(0);
637 TCGv t3
= tcg_const_tl(1);
639 tcg_gen_ext32u_tl(t0
, load_gpr(dc
, instr
.a
));
640 tcg_gen_ext32u_tl(t1
, load_gpr(dc
, instr
.b
));
641 tcg_gen_movcond_tl(TCG_COND_EQ
, t1
, t1
, t2
, t3
, t1
);
642 tcg_gen_divu_tl(dc
->cpu_R
[instr
.c
], t0
, t1
);
643 tcg_gen_ext32s_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.c
]);
651 static const Nios2Instruction r_type_instructions
[] = {
652 INSTRUCTION_ILLEGAL(),
653 INSTRUCTION(eret
), /* eret */
654 INSTRUCTION(roli
), /* roli */
655 INSTRUCTION(rol
), /* rol */
656 INSTRUCTION_NOP(), /* flushp */
657 INSTRUCTION(ret
), /* ret */
658 INSTRUCTION(nor
), /* nor */
659 INSTRUCTION(mulxuu
), /* mulxuu */
660 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GE
), /* cmpge */
661 INSTRUCTION(bret
), /* bret */
662 INSTRUCTION_ILLEGAL(),
663 INSTRUCTION(ror
), /* ror */
664 INSTRUCTION_NOP(), /* flushi */
665 INSTRUCTION(jmp
), /* jmp */
666 INSTRUCTION(and), /* and */
667 INSTRUCTION_ILLEGAL(),
668 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LT
), /* cmplt */
669 INSTRUCTION_ILLEGAL(),
670 INSTRUCTION(slli
), /* slli */
671 INSTRUCTION(sll
), /* sll */
672 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
673 INSTRUCTION_ILLEGAL(),
674 INSTRUCTION(or), /* or */
675 INSTRUCTION(mulxsu
), /* mulxsu */
676 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_NE
), /* cmpne */
677 INSTRUCTION_ILLEGAL(),
678 INSTRUCTION(srli
), /* srli */
679 INSTRUCTION(srl
), /* srl */
680 INSTRUCTION(nextpc
), /* nextpc */
681 INSTRUCTION(callr
), /* callr */
682 INSTRUCTION(xor), /* xor */
683 INSTRUCTION(mulxss
), /* mulxss */
684 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_EQ
), /* cmpeq */
685 INSTRUCTION_ILLEGAL(),
686 INSTRUCTION_ILLEGAL(),
687 INSTRUCTION_ILLEGAL(),
688 INSTRUCTION(divu
), /* divu */
689 INSTRUCTION(divs
), /* div */
690 INSTRUCTION(rdctl
), /* rdctl */
691 INSTRUCTION(mul
), /* mul */
692 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GEU
), /* cmpgeu */
693 INSTRUCTION_NOP(), /* initi */
694 INSTRUCTION_ILLEGAL(),
695 INSTRUCTION_ILLEGAL(),
696 INSTRUCTION_ILLEGAL(),
697 INSTRUCTION_FLG(gen_excp
, EXCP_TRAP
), /* trap */
698 INSTRUCTION(wrctl
), /* wrctl */
699 INSTRUCTION_ILLEGAL(),
700 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LTU
), /* cmpltu */
701 INSTRUCTION(add
), /* add */
702 INSTRUCTION_ILLEGAL(),
703 INSTRUCTION_ILLEGAL(),
704 INSTRUCTION_FLG(gen_excp
, EXCP_BREAK
), /* break */
705 INSTRUCTION_ILLEGAL(),
706 INSTRUCTION(nop
), /* nop */
707 INSTRUCTION_ILLEGAL(),
708 INSTRUCTION_ILLEGAL(),
709 INSTRUCTION(sub
), /* sub */
710 INSTRUCTION(srai
), /* srai */
711 INSTRUCTION(sra
), /* sra */
712 INSTRUCTION_ILLEGAL(),
713 INSTRUCTION_ILLEGAL(),
714 INSTRUCTION_ILLEGAL(),
715 INSTRUCTION_ILLEGAL(),
718 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
721 const Nios2Instruction
*instr
;
723 opx
= get_opxcode(code
);
724 if (unlikely(opx
>= ARRAY_SIZE(r_type_instructions
))) {
728 instr
= &r_type_instructions
[opx
];
729 instr
->handler(dc
, code
, instr
->flags
);
734 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
737 static void handle_instruction(DisasContext
*dc
, CPUNios2State
*env
)
741 const Nios2Instruction
*instr
;
742 #if defined(CONFIG_USER_ONLY)
743 /* FIXME: Is this needed ? */
744 if (dc
->pc
>= 0x1000 && dc
->pc
< 0x2000) {
745 env
->regs
[R_PC
] = dc
->pc
;
746 t_gen_helper_raise_exception(dc
, 0xaa);
750 code
= cpu_ldl_code(env
, dc
->pc
);
751 op
= get_opcode(code
);
753 if (unlikely(op
>= ARRAY_SIZE(i_type_instructions
))) {
757 TCGV_UNUSED_I32(dc
->zero
);
759 instr
= &i_type_instructions
[op
];
760 instr
->handler(dc
, code
, instr
->flags
);
762 if (!TCGV_IS_UNUSED_I32(dc
->zero
)) {
763 tcg_temp_free(dc
->zero
);
769 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
772 static const char * const regnames
[] = {
773 "zero", "at", "r2", "r3",
774 "r4", "r5", "r6", "r7",
775 "r8", "r9", "r10", "r11",
776 "r12", "r13", "r14", "r15",
777 "r16", "r17", "r18", "r19",
778 "r20", "r21", "r22", "r23",
779 "et", "bt", "gp", "sp",
780 "fp", "ea", "ba", "ra",
781 "status", "estatus", "bstatus", "ienable",
782 "ipending", "cpuid", "reserved0", "exception",
783 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
784 "badaddr", "config", "mpubase", "mpuacc",
785 "reserved2", "reserved3", "reserved4", "reserved5",
786 "reserved6", "reserved7", "reserved8", "reserved9",
787 "reserved10", "reserved11", "reserved12", "reserved13",
788 "reserved14", "reserved15", "reserved16", "reserved17",
792 static TCGv_ptr cpu_env
;
793 static TCGv cpu_R
[NUM_CORE_REGS
];
795 #include "exec/gen-icount.h"
797 static void gen_exception(DisasContext
*dc
, uint32_t excp
)
799 TCGv_i32 tmp
= tcg_const_i32(excp
);
801 tcg_gen_movi_tl(cpu_R
[R_PC
], dc
->pc
);
802 gen_helper_raise_exception(cpu_env
, tmp
);
803 tcg_temp_free_i32(tmp
);
804 dc
->is_jmp
= DISAS_UPDATE
;
807 /* generate intermediate code for basic block 'tb'. */
808 void gen_intermediate_code(CPUState
*cs
, TranslationBlock
*tb
)
810 CPUNios2State
*env
= cs
->env_ptr
;
811 DisasContext dc1
, *dc
= &dc1
;
816 dc
->cpu_env
= cpu_env
;
818 dc
->is_jmp
= DISAS_NEXT
;
821 dc
->mem_idx
= cpu_mmu_index(env
, false);
822 dc
->singlestep_enabled
= cs
->singlestep_enabled
;
824 /* Set up instruction counts */
826 if (cs
->singlestep_enabled
|| singlestep
) {
829 int page_insns
= (TARGET_PAGE_SIZE
- (tb
->pc
& TARGET_PAGE_MASK
)) / 4;
830 max_insns
= tb
->cflags
& CF_COUNT_MASK
;
831 if (max_insns
== 0) {
832 max_insns
= CF_COUNT_MASK
;
834 if (max_insns
> page_insns
) {
835 max_insns
= page_insns
;
837 if (max_insns
> TCG_MAX_INSNS
) {
838 max_insns
= TCG_MAX_INSNS
;
844 tcg_gen_insn_start(dc
->pc
);
847 if (unlikely(cpu_breakpoint_test(cs
, dc
->pc
, BP_ANY
))) {
848 gen_exception(dc
, EXCP_DEBUG
);
849 /* The address covered by the breakpoint must be included in
850 [tb->pc, tb->pc + tb->size) in order to for it to be
851 properly cleared -- thus we increment the PC here so that
852 the logic setting tb->size below does the right thing. */
857 if (num_insns
== max_insns
&& (tb
->cflags
& CF_LAST_IO
)) {
861 /* Decode an instruction */
862 handle_instruction(dc
, env
);
866 /* Translation stops when a conditional branch is encountered.
867 * Otherwise the subsequent code could get translated several times.
868 * Also stop translation when a page boundary is reached. This
869 * ensures prefetch aborts occur at the right place. */
870 } while (!dc
->is_jmp
&&
871 !tcg_op_buf_full() &&
872 num_insns
< max_insns
);
874 if (tb
->cflags
& CF_LAST_IO
) {
878 /* Indicate where the next block should start */
879 switch (dc
->is_jmp
) {
881 /* Save the current PC back into the CPU register */
882 tcg_gen_movi_tl(cpu_R
[R_PC
], dc
->pc
);
889 /* The jump will already have updated the PC register */
894 /* nothing more to generate */
898 /* End off the block */
899 gen_tb_end(tb
, num_insns
);
901 /* Mark instruction starts for the final generated instruction */
902 tb
->size
= dc
->pc
- tb
->pc
;
903 tb
->icount
= num_insns
;
906 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)
907 && qemu_log_in_addr_range(tb
->pc
)) {
909 qemu_log("IN: %s\n", lookup_symbol(tb
->pc
));
910 log_target_disas(cs
, tb
->pc
, dc
->pc
- tb
->pc
, 0);
917 void nios2_cpu_dump_state(CPUState
*cs
, FILE *f
, fprintf_function cpu_fprintf
,
920 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
921 CPUNios2State
*env
= &cpu
->env
;
928 cpu_fprintf(f
, "IN: PC=%x %s\n",
929 env
->regs
[R_PC
], lookup_symbol(env
->regs
[R_PC
]));
931 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
932 cpu_fprintf(f
, "%9s=%8.8x ", regnames
[i
], env
->regs
[i
]);
933 if ((i
+ 1) % 4 == 0) {
934 cpu_fprintf(f
, "\n");
937 #if !defined(CONFIG_USER_ONLY)
938 cpu_fprintf(f
, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
939 env
->mmu
.pteaddr_wr
& CR_PTEADDR_VPN_MASK
,
940 (env
->mmu
.tlbmisc_wr
& CR_TLBMISC_PID_MASK
) >> 4,
943 cpu_fprintf(f
, "\n\n");
946 void nios2_tcg_init(void)
950 cpu_env
= tcg_global_reg_new_ptr(TCG_AREG0
, "env");
952 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
953 cpu_R
[i
] = tcg_global_mem_new(cpu_env
,
954 offsetof(CPUNios2State
, regs
[i
]),
959 void restore_state_to_opc(CPUNios2State
*env
, TranslationBlock
*tb
,
962 env
->regs
[R_PC
] = data
[0];