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"
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"
35 /* is_jmp field values */
36 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
37 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
38 #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
40 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
41 #define INSTRUCTION(func) \
42 INSTRUCTION_FLG(func, 0)
43 #define INSTRUCTION_NOP() \
44 INSTRUCTION_FLG(nop, 0)
45 #define INSTRUCTION_UNIMPLEMENTED() \
46 INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
47 #define INSTRUCTION_ILLEGAL() \
48 INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
50 /* Special R-Type instruction opcode */
51 #define INSN_R_TYPE 0x3A
53 /* I-Type instruction parsing */
54 #define I_TYPE(instr, code) \
64 .op = extract32((code), 0, 6), \
65 .imm16.u = extract32((code), 6, 16), \
66 .b = extract32((code), 22, 5), \
67 .a = extract32((code), 27, 5), \
70 /* R-Type instruction parsing */
71 #define R_TYPE(instr, code) \
80 .op = extract32((code), 0, 6), \
81 .imm5 = extract32((code), 6, 5), \
82 .opx = extract32((code), 11, 6), \
83 .c = extract32((code), 17, 5), \
84 .b = extract32((code), 22, 5), \
85 .a = extract32((code), 27, 5), \
88 /* J-Type instruction parsing */
89 #define J_TYPE(instr, code) \
94 .op = extract32((code), 0, 6), \
95 .imm26 = extract32((code), 6, 26), \
98 typedef struct DisasContext
{
104 TranslationBlock
*tb
;
106 bool singlestep_enabled
;
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
)) {
137 return dc
->cpu_R
[reg
];
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(dc
->cpu_R
[R_PC
], dc
->pc
);
149 gen_helper_raise_exception(dc
->cpu_env
, tmp
);
150 tcg_temp_free_i32(tmp
);
151 dc
->is_jmp
= DISAS_UPDATE
;
154 static bool use_goto_tb(DisasContext
*dc
, uint32_t dest
)
156 if (unlikely(dc
->singlestep_enabled
)) {
160 #ifndef CONFIG_USER_ONLY
161 return (dc
->tb
->pc
& TARGET_PAGE_MASK
) == (dest
& TARGET_PAGE_MASK
);
167 static void gen_goto_tb(DisasContext
*dc
, int n
, uint32_t dest
)
169 TranslationBlock
*tb
= dc
->tb
;
171 if (use_goto_tb(dc
, dest
)) {
173 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dest
);
174 tcg_gen_exit_tb(tb
, n
);
176 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dest
);
177 tcg_gen_exit_tb(NULL
, 0);
181 static void gen_excp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
183 t_gen_helper_raise_exception(dc
, flags
);
186 static void gen_check_supervisor(DisasContext
*dc
)
188 if (dc
->tb
->flags
& CR_STATUS_U
) {
189 /* CPU in user mode, privileged instruction called, stop. */
190 t_gen_helper_raise_exception(dc
, EXCP_SUPERI
);
195 * Used as a placeholder for all instructions which do not have
196 * an effect on the simulator (e.g. flush, sync)
198 static void nop(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
200 /* Nothing to do here */
204 * J-Type instructions
206 static void jmpi(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
209 gen_goto_tb(dc
, 0, (dc
->pc
& 0xF0000000) | (instr
.imm26
<< 2));
210 dc
->is_jmp
= DISAS_TB_JUMP
;
213 static void call(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
215 tcg_gen_movi_tl(dc
->cpu_R
[R_RA
], dc
->pc
+ 4);
216 jmpi(dc
, code
, flags
);
220 * I-Type instructions
222 /* Load instructions */
223 static void gen_ldx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
227 TCGv addr
= tcg_temp_new();
231 * WARNING: Loads into R_ZERO are ignored, but we must generate the
232 * memory access itself to emulate the CPU precisely. Load
233 * from a protected page to R_ZERO will cause SIGSEGV on
236 if (likely(instr
.b
!= R_ZERO
)) {
237 data
= dc
->cpu_R
[instr
.b
];
239 data
= tcg_temp_new();
242 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
243 tcg_gen_qemu_ld_tl(data
, addr
, dc
->mem_idx
, flags
);
245 if (unlikely(instr
.b
== R_ZERO
)) {
252 /* Store instructions */
253 static void gen_stx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
256 TCGv val
= load_gpr(dc
, instr
.b
);
258 TCGv addr
= tcg_temp_new();
259 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
260 tcg_gen_qemu_st_tl(val
, addr
, dc
->mem_idx
, flags
);
264 /* Branch instructions */
265 static void br(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
269 gen_goto_tb(dc
, 0, dc
->pc
+ 4 + (instr
.imm16
.s
& -4));
270 dc
->is_jmp
= DISAS_TB_JUMP
;
273 static void gen_bxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
277 TCGLabel
*l1
= gen_new_label();
278 tcg_gen_brcond_tl(flags
, dc
->cpu_R
[instr
.a
], dc
->cpu_R
[instr
.b
], l1
);
279 gen_goto_tb(dc
, 0, dc
->pc
+ 4);
281 gen_goto_tb(dc
, 1, dc
->pc
+ 4 + (instr
.imm16
.s
& -4));
282 dc
->is_jmp
= DISAS_TB_JUMP
;
285 /* Comparison instructions */
286 #define gen_i_cmpxx(fname, op3) \
287 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
289 I_TYPE(instr, (code)); \
290 tcg_gen_setcondi_tl(flags, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
294 gen_i_cmpxx(gen_cmpxxsi
, instr
.imm16
.s
)
295 gen_i_cmpxx(gen_cmpxxui
, instr
.imm16
.u
)
297 /* Math/logic instructions */
298 #define gen_i_math_logic(fname, insn, resimm, op3) \
299 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
301 I_TYPE(instr, (code)); \
302 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
304 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
305 tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0); \
307 tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
312 gen_i_math_logic(addi
, addi
, 1, instr
.imm16
.s
)
313 gen_i_math_logic(muli
, muli
, 0, instr
.imm16
.s
)
315 gen_i_math_logic(andi
, andi
, 0, instr
.imm16
.u
)
316 gen_i_math_logic(ori
, ori
, 1, instr
.imm16
.u
)
317 gen_i_math_logic(xori
, xori
, 1, instr
.imm16
.u
)
319 gen_i_math_logic(andhi
, andi
, 0, instr
.imm16
.u
<< 16)
320 gen_i_math_logic(orhi
, ori
, 1, instr
.imm16
.u
<< 16)
321 gen_i_math_logic(xorhi
, xori
, 1, instr
.imm16
.u
<< 16)
323 /* Prototype only, defined below */
324 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
,
327 static const Nios2Instruction i_type_instructions
[] = {
328 INSTRUCTION(call
), /* call */
329 INSTRUCTION(jmpi
), /* jmpi */
330 INSTRUCTION_ILLEGAL(),
331 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbu */
332 INSTRUCTION(addi
), /* addi */
333 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stb */
334 INSTRUCTION(br
), /* br */
335 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldb */
336 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_GE
), /* cmpgei */
337 INSTRUCTION_ILLEGAL(),
338 INSTRUCTION_ILLEGAL(),
339 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhu */
340 INSTRUCTION(andi
), /* andi */
341 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sth */
342 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GE
), /* bge */
343 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldh */
344 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_LT
), /* cmplti */
345 INSTRUCTION_ILLEGAL(),
346 INSTRUCTION_ILLEGAL(),
347 INSTRUCTION_NOP(), /* initda */
348 INSTRUCTION(ori
), /* ori */
349 INSTRUCTION_FLG(gen_stx
, MO_UL
), /* stw */
350 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LT
), /* blt */
351 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldw */
352 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_NE
), /* cmpnei */
353 INSTRUCTION_ILLEGAL(),
354 INSTRUCTION_ILLEGAL(),
355 INSTRUCTION_NOP(), /* flushda */
356 INSTRUCTION(xori
), /* xori */
357 INSTRUCTION_ILLEGAL(),
358 INSTRUCTION_FLG(gen_bxx
, TCG_COND_NE
), /* bne */
359 INSTRUCTION_ILLEGAL(),
360 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_EQ
), /* cmpeqi */
361 INSTRUCTION_ILLEGAL(),
362 INSTRUCTION_ILLEGAL(),
363 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbuio */
364 INSTRUCTION(muli
), /* muli */
365 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stbio */
366 INSTRUCTION_FLG(gen_bxx
, TCG_COND_EQ
), /* beq */
367 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldbio */
368 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_GEU
), /* cmpgeui */
369 INSTRUCTION_ILLEGAL(),
370 INSTRUCTION_ILLEGAL(),
371 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhuio */
372 INSTRUCTION(andhi
), /* andhi */
373 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sthio */
374 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GEU
), /* bgeu */
375 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldhio */
376 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_LTU
), /* cmpltui */
377 INSTRUCTION_ILLEGAL(),
378 INSTRUCTION_UNIMPLEMENTED(), /* custom */
379 INSTRUCTION_NOP(), /* initd */
380 INSTRUCTION(orhi
), /* orhi */
381 INSTRUCTION_FLG(gen_stx
, MO_SL
), /* stwio */
382 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LTU
), /* bltu */
383 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldwio */
384 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
385 INSTRUCTION_ILLEGAL(),
386 INSTRUCTION_FLG(handle_r_type_instr
, 0), /* R-Type */
387 INSTRUCTION_NOP(), /* flushd */
388 INSTRUCTION(xorhi
), /* xorhi */
389 INSTRUCTION_ILLEGAL(),
390 INSTRUCTION_ILLEGAL(),
391 INSTRUCTION_ILLEGAL(),
395 * R-Type instructions
401 static void eret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
403 tcg_gen_mov_tl(dc
->cpu_R
[CR_STATUS
], dc
->cpu_R
[CR_ESTATUS
]);
404 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_EA
]);
406 dc
->is_jmp
= DISAS_JUMP
;
410 static void ret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
412 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_RA
]);
414 dc
->is_jmp
= DISAS_JUMP
;
418 static void bret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
420 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_BA
]);
422 dc
->is_jmp
= DISAS_JUMP
;
426 static void jmp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
430 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
432 dc
->is_jmp
= DISAS_JUMP
;
436 static void nextpc(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
440 if (likely(instr
.c
!= R_ZERO
)) {
441 tcg_gen_movi_tl(dc
->cpu_R
[instr
.c
], dc
->pc
+ 4);
449 static void callr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
453 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
454 tcg_gen_movi_tl(dc
->cpu_R
[R_RA
], dc
->pc
+ 4);
456 dc
->is_jmp
= DISAS_JUMP
;
460 static void rdctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
464 gen_check_supervisor(dc
);
466 switch (instr
.imm5
+ CR_BASE
) {
471 #if !defined(CONFIG_USER_ONLY)
472 if (likely(instr
.c
!= R_ZERO
)) {
473 tcg_gen_mov_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.imm5
+ CR_BASE
]);
475 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
476 gen_helper_mmu_read_debug(dc
->cpu_R
[instr
.c
], dc
->cpu_env
, tmp
);
477 tcg_temp_free_i32(tmp
);
485 if (likely(instr
.c
!= R_ZERO
)) {
486 tcg_gen_mov_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.imm5
+ CR_BASE
]);
493 static void wrctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
497 gen_check_supervisor(dc
);
499 switch (instr
.imm5
+ CR_BASE
) {
504 #if !defined(CONFIG_USER_ONLY)
505 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
506 gen_helper_mmu_write(dc
->cpu_env
, tmp
, load_gpr(dc
, instr
.a
));
507 tcg_temp_free_i32(tmp
);
513 tcg_gen_mov_tl(dc
->cpu_R
[instr
.imm5
+ CR_BASE
], load_gpr(dc
, instr
.a
));
517 /* If interrupts were enabled using WRCTL, trigger them. */
518 #if !defined(CONFIG_USER_ONLY)
519 if ((instr
.imm5
+ CR_BASE
) == CR_STATUS
) {
520 gen_helper_check_interrupts(dc
->cpu_env
);
525 /* Comparison instructions */
526 static void gen_cmpxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
529 if (likely(instr
.c
!= R_ZERO
)) {
530 tcg_gen_setcond_tl(flags
, dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.a
],
535 /* Math/logic instructions */
536 #define gen_r_math_logic(fname, insn, op3) \
537 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
539 R_TYPE(instr, (code)); \
540 if (likely(instr.c != R_ZERO)) { \
541 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), \
546 gen_r_math_logic(add
, add_tl
, load_gpr(dc
, instr
.b
))
547 gen_r_math_logic(sub
, sub_tl
, load_gpr(dc
, instr
.b
))
548 gen_r_math_logic(mul
, mul_tl
, load_gpr(dc
, instr
.b
))
550 gen_r_math_logic(and, and_tl
, load_gpr(dc
, instr
.b
))
551 gen_r_math_logic(or, or_tl
, load_gpr(dc
, instr
.b
))
552 gen_r_math_logic(xor, xor_tl
, load_gpr(dc
, instr
.b
))
553 gen_r_math_logic(nor
, nor_tl
, load_gpr(dc
, instr
.b
))
555 gen_r_math_logic(srai
, sari_tl
, instr
.imm5
)
556 gen_r_math_logic(srli
, shri_tl
, instr
.imm5
)
557 gen_r_math_logic(slli
, shli_tl
, instr
.imm5
)
558 gen_r_math_logic(roli
, rotli_tl
, instr
.imm5
)
560 #define gen_r_mul(fname, insn) \
561 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
563 R_TYPE(instr, (code)); \
564 if (likely(instr.c != R_ZERO)) { \
565 TCGv t0 = tcg_temp_new(); \
566 tcg_gen_##insn(t0, dc->cpu_R[instr.c], \
567 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
572 gen_r_mul(mulxss
, muls2_tl
)
573 gen_r_mul(mulxuu
, mulu2_tl
)
574 gen_r_mul(mulxsu
, mulsu2_tl
)
576 #define gen_r_shift_s(fname, insn) \
577 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
579 R_TYPE(instr, (code)); \
580 if (likely(instr.c != R_ZERO)) { \
581 TCGv t0 = tcg_temp_new(); \
582 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
583 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
588 gen_r_shift_s(sra
, sar_tl
)
589 gen_r_shift_s(srl
, shr_tl
)
590 gen_r_shift_s(sll
, shl_tl
)
591 gen_r_shift_s(rol
, rotl_tl
)
592 gen_r_shift_s(ror
, rotr_tl
)
594 static void divs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
596 R_TYPE(instr
, (code
));
598 /* Stores into R_ZERO are ignored */
599 if (unlikely(instr
.c
== R_ZERO
)) {
603 TCGv t0
= tcg_temp_new();
604 TCGv t1
= tcg_temp_new();
605 TCGv t2
= tcg_temp_new();
606 TCGv t3
= tcg_temp_new();
608 tcg_gen_ext32s_tl(t0
, load_gpr(dc
, instr
.a
));
609 tcg_gen_ext32s_tl(t1
, load_gpr(dc
, instr
.b
));
610 tcg_gen_setcondi_tl(TCG_COND_EQ
, t2
, t0
, INT_MIN
);
611 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, -1);
612 tcg_gen_and_tl(t2
, t2
, t3
);
613 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, 0);
614 tcg_gen_or_tl(t2
, t2
, t3
);
615 tcg_gen_movi_tl(t3
, 0);
616 tcg_gen_movcond_tl(TCG_COND_NE
, t1
, t2
, t3
, t2
, t1
);
617 tcg_gen_div_tl(dc
->cpu_R
[instr
.c
], t0
, t1
);
618 tcg_gen_ext32s_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.c
]);
626 static void divu(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
628 R_TYPE(instr
, (code
));
630 /* Stores into R_ZERO are ignored */
631 if (unlikely(instr
.c
== R_ZERO
)) {
635 TCGv t0
= tcg_temp_new();
636 TCGv t1
= tcg_temp_new();
637 TCGv t2
= tcg_const_tl(0);
638 TCGv t3
= tcg_const_tl(1);
640 tcg_gen_ext32u_tl(t0
, load_gpr(dc
, instr
.a
));
641 tcg_gen_ext32u_tl(t1
, load_gpr(dc
, instr
.b
));
642 tcg_gen_movcond_tl(TCG_COND_EQ
, t1
, t1
, t2
, t3
, t1
);
643 tcg_gen_divu_tl(dc
->cpu_R
[instr
.c
], t0
, t1
);
644 tcg_gen_ext32s_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.c
]);
652 static const Nios2Instruction r_type_instructions
[] = {
653 INSTRUCTION_ILLEGAL(),
654 INSTRUCTION(eret
), /* eret */
655 INSTRUCTION(roli
), /* roli */
656 INSTRUCTION(rol
), /* rol */
657 INSTRUCTION_NOP(), /* flushp */
658 INSTRUCTION(ret
), /* ret */
659 INSTRUCTION(nor
), /* nor */
660 INSTRUCTION(mulxuu
), /* mulxuu */
661 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GE
), /* cmpge */
662 INSTRUCTION(bret
), /* bret */
663 INSTRUCTION_ILLEGAL(),
664 INSTRUCTION(ror
), /* ror */
665 INSTRUCTION_NOP(), /* flushi */
666 INSTRUCTION(jmp
), /* jmp */
667 INSTRUCTION(and), /* and */
668 INSTRUCTION_ILLEGAL(),
669 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LT
), /* cmplt */
670 INSTRUCTION_ILLEGAL(),
671 INSTRUCTION(slli
), /* slli */
672 INSTRUCTION(sll
), /* sll */
673 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
674 INSTRUCTION_ILLEGAL(),
675 INSTRUCTION(or), /* or */
676 INSTRUCTION(mulxsu
), /* mulxsu */
677 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_NE
), /* cmpne */
678 INSTRUCTION_ILLEGAL(),
679 INSTRUCTION(srli
), /* srli */
680 INSTRUCTION(srl
), /* srl */
681 INSTRUCTION(nextpc
), /* nextpc */
682 INSTRUCTION(callr
), /* callr */
683 INSTRUCTION(xor), /* xor */
684 INSTRUCTION(mulxss
), /* mulxss */
685 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_EQ
), /* cmpeq */
686 INSTRUCTION_ILLEGAL(),
687 INSTRUCTION_ILLEGAL(),
688 INSTRUCTION_ILLEGAL(),
689 INSTRUCTION(divu
), /* divu */
690 INSTRUCTION(divs
), /* div */
691 INSTRUCTION(rdctl
), /* rdctl */
692 INSTRUCTION(mul
), /* mul */
693 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GEU
), /* cmpgeu */
694 INSTRUCTION_NOP(), /* initi */
695 INSTRUCTION_ILLEGAL(),
696 INSTRUCTION_ILLEGAL(),
697 INSTRUCTION_ILLEGAL(),
698 INSTRUCTION_FLG(gen_excp
, EXCP_TRAP
), /* trap */
699 INSTRUCTION(wrctl
), /* wrctl */
700 INSTRUCTION_ILLEGAL(),
701 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LTU
), /* cmpltu */
702 INSTRUCTION(add
), /* add */
703 INSTRUCTION_ILLEGAL(),
704 INSTRUCTION_ILLEGAL(),
705 INSTRUCTION_FLG(gen_excp
, EXCP_BREAK
), /* break */
706 INSTRUCTION_ILLEGAL(),
707 INSTRUCTION(nop
), /* nop */
708 INSTRUCTION_ILLEGAL(),
709 INSTRUCTION_ILLEGAL(),
710 INSTRUCTION(sub
), /* sub */
711 INSTRUCTION(srai
), /* srai */
712 INSTRUCTION(sra
), /* sra */
713 INSTRUCTION_ILLEGAL(),
714 INSTRUCTION_ILLEGAL(),
715 INSTRUCTION_ILLEGAL(),
716 INSTRUCTION_ILLEGAL(),
719 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
722 const Nios2Instruction
*instr
;
724 opx
= get_opxcode(code
);
725 if (unlikely(opx
>= ARRAY_SIZE(r_type_instructions
))) {
729 instr
= &r_type_instructions
[opx
];
730 instr
->handler(dc
, code
, instr
->flags
);
735 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
738 static void handle_instruction(DisasContext
*dc
, CPUNios2State
*env
)
742 const Nios2Instruction
*instr
;
743 #if defined(CONFIG_USER_ONLY)
744 /* FIXME: Is this needed ? */
745 if (dc
->pc
>= 0x1000 && dc
->pc
< 0x2000) {
746 env
->regs
[R_PC
] = dc
->pc
;
747 t_gen_helper_raise_exception(dc
, 0xaa);
751 code
= cpu_ldl_code(env
, dc
->pc
);
752 op
= get_opcode(code
);
754 if (unlikely(op
>= ARRAY_SIZE(i_type_instructions
))) {
760 instr
= &i_type_instructions
[op
];
761 instr
->handler(dc
, code
, instr
->flags
);
764 tcg_temp_free(dc
->zero
);
770 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
773 static const char * const regnames
[] = {
774 "zero", "at", "r2", "r3",
775 "r4", "r5", "r6", "r7",
776 "r8", "r9", "r10", "r11",
777 "r12", "r13", "r14", "r15",
778 "r16", "r17", "r18", "r19",
779 "r20", "r21", "r22", "r23",
780 "et", "bt", "gp", "sp",
781 "fp", "ea", "ba", "ra",
782 "status", "estatus", "bstatus", "ienable",
783 "ipending", "cpuid", "reserved0", "exception",
784 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
785 "badaddr", "config", "mpubase", "mpuacc",
786 "reserved2", "reserved3", "reserved4", "reserved5",
787 "reserved6", "reserved7", "reserved8", "reserved9",
788 "reserved10", "reserved11", "reserved12", "reserved13",
789 "reserved14", "reserved15", "reserved16", "reserved17",
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(tb
) & 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(tb
) & 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(tb
) & 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
);
883 tcg_gen_exit_tb(NULL
, 0);
889 /* The jump will already have updated the PC register */
890 tcg_gen_exit_tb(NULL
, 0);
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
);
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 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
951 cpu_R
[i
] = tcg_global_mem_new(cpu_env
,
952 offsetof(CPUNios2State
, regs
[i
]),
957 void restore_state_to_opc(CPUNios2State
*env
, TranslationBlock
*tb
,
960 env
->regs
[R_PC
] = data
[0];