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"
33 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
34 #define INSTRUCTION(func) \
35 INSTRUCTION_FLG(func, 0)
36 #define INSTRUCTION_NOP() \
37 INSTRUCTION_FLG(nop, 0)
38 #define INSTRUCTION_UNIMPLEMENTED() \
39 INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
40 #define INSTRUCTION_ILLEGAL() \
41 INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
43 /* Special R-Type instruction opcode */
44 #define INSN_R_TYPE 0x3A
46 /* I-Type instruction parsing */
47 #define I_TYPE(instr, code) \
57 .op = extract32((code), 0, 6), \
58 .imm16.u = extract32((code), 6, 16), \
59 .b = extract32((code), 22, 5), \
60 .a = extract32((code), 27, 5), \
63 /* R-Type instruction parsing */
64 #define R_TYPE(instr, code) \
73 .op = extract32((code), 0, 6), \
74 .imm5 = extract32((code), 6, 5), \
75 .opx = extract32((code), 11, 6), \
76 .c = extract32((code), 17, 5), \
77 .b = extract32((code), 22, 5), \
78 .a = extract32((code), 27, 5), \
81 /* J-Type instruction parsing */
82 #define J_TYPE(instr, code) \
87 .op = extract32((code), 0, 6), \
88 .imm26 = extract32((code), 6, 26), \
91 typedef struct DisasContext
{
99 bool singlestep_enabled
;
102 typedef struct Nios2Instruction
{
103 void (*handler
)(DisasContext
*dc
, uint32_t code
, uint32_t flags
);
107 static uint8_t get_opcode(uint32_t code
)
113 static uint8_t get_opxcode(uint32_t code
)
119 static TCGv
load_zero(DisasContext
*dc
)
121 if (TCGV_IS_UNUSED_I32(dc
->zero
)) {
122 dc
->zero
= tcg_const_i32(0);
127 static TCGv
load_gpr(DisasContext
*dc
, uint8_t reg
)
129 if (likely(reg
!= R_ZERO
)) {
130 return dc
->cpu_R
[reg
];
132 return load_zero(dc
);
136 static void t_gen_helper_raise_exception(DisasContext
*dc
,
139 TCGv_i32 tmp
= tcg_const_i32(index
);
141 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dc
->pc
);
142 gen_helper_raise_exception(dc
->cpu_env
, tmp
);
143 tcg_temp_free_i32(tmp
);
144 dc
->is_jmp
= DISAS_UPDATE
;
147 static bool use_goto_tb(DisasContext
*dc
, uint32_t dest
)
149 if (unlikely(dc
->singlestep_enabled
)) {
153 #ifndef CONFIG_USER_ONLY
154 return (dc
->tb
->pc
& TARGET_PAGE_MASK
) == (dest
& TARGET_PAGE_MASK
);
160 static void gen_goto_tb(DisasContext
*dc
, int n
, uint32_t dest
)
162 TranslationBlock
*tb
= dc
->tb
;
164 if (use_goto_tb(dc
, dest
)) {
166 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dest
);
167 tcg_gen_exit_tb((uintptr_t)tb
+ n
);
169 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dest
);
174 static void gen_excp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
176 t_gen_helper_raise_exception(dc
, flags
);
179 static void gen_check_supervisor(DisasContext
*dc
)
181 if (dc
->tb
->flags
& CR_STATUS_U
) {
182 /* CPU in user mode, privileged instruction called, stop. */
183 t_gen_helper_raise_exception(dc
, EXCP_SUPERI
);
188 * Used as a placeholder for all instructions which do not have
189 * an effect on the simulator (e.g. flush, sync)
191 static void nop(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
193 /* Nothing to do here */
197 * J-Type instructions
199 static void jmpi(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
202 gen_goto_tb(dc
, 0, (dc
->pc
& 0xF0000000) | (instr
.imm26
<< 2));
203 dc
->is_jmp
= DISAS_TB_JUMP
;
206 static void call(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
208 tcg_gen_movi_tl(dc
->cpu_R
[R_RA
], dc
->pc
+ 4);
209 jmpi(dc
, code
, flags
);
213 * I-Type instructions
215 /* Load instructions */
216 static void gen_ldx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
220 TCGv addr
= tcg_temp_new();
224 * WARNING: Loads into R_ZERO are ignored, but we must generate the
225 * memory access itself to emulate the CPU precisely. Load
226 * from a protected page to R_ZERO will cause SIGSEGV on
229 if (likely(instr
.b
!= R_ZERO
)) {
230 data
= dc
->cpu_R
[instr
.b
];
232 data
= tcg_temp_new();
235 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
236 tcg_gen_qemu_ld_tl(data
, addr
, dc
->mem_idx
, flags
);
238 if (unlikely(instr
.b
== R_ZERO
)) {
245 /* Store instructions */
246 static void gen_stx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
249 TCGv val
= load_gpr(dc
, instr
.b
);
251 TCGv addr
= tcg_temp_new();
252 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
253 tcg_gen_qemu_st_tl(val
, addr
, dc
->mem_idx
, flags
);
257 /* Branch instructions */
258 static void br(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
262 gen_goto_tb(dc
, 0, dc
->pc
+ 4 + (instr
.imm16
.s
& -4));
263 dc
->is_jmp
= DISAS_TB_JUMP
;
266 static void gen_bxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
270 TCGLabel
*l1
= gen_new_label();
271 tcg_gen_brcond_tl(flags
, dc
->cpu_R
[instr
.a
], dc
->cpu_R
[instr
.b
], l1
);
272 gen_goto_tb(dc
, 0, dc
->pc
+ 4);
274 gen_goto_tb(dc
, 1, dc
->pc
+ 4 + (instr
.imm16
.s
& -4));
275 dc
->is_jmp
= DISAS_TB_JUMP
;
278 /* Comparison instructions */
279 #define gen_i_cmpxx(fname, op3) \
280 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
282 I_TYPE(instr, (code)); \
283 tcg_gen_setcondi_tl(flags, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
287 gen_i_cmpxx(gen_cmpxxsi
, instr
.imm16
.s
)
288 gen_i_cmpxx(gen_cmpxxui
, instr
.imm16
.u
)
290 /* Math/logic instructions */
291 #define gen_i_math_logic(fname, insn, resimm, op3) \
292 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
294 I_TYPE(instr, (code)); \
295 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
297 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
298 tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0); \
300 tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
305 gen_i_math_logic(addi
, addi
, 1, instr
.imm16
.s
)
306 gen_i_math_logic(muli
, muli
, 0, instr
.imm16
.s
)
308 gen_i_math_logic(andi
, andi
, 0, instr
.imm16
.u
)
309 gen_i_math_logic(ori
, ori
, 1, instr
.imm16
.u
)
310 gen_i_math_logic(xori
, xori
, 1, instr
.imm16
.u
)
312 gen_i_math_logic(andhi
, andi
, 0, instr
.imm16
.u
<< 16)
313 gen_i_math_logic(orhi
, ori
, 1, instr
.imm16
.u
<< 16)
314 gen_i_math_logic(xorhi
, xori
, 1, instr
.imm16
.u
<< 16)
316 /* Prototype only, defined below */
317 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
,
320 static const Nios2Instruction i_type_instructions
[] = {
321 INSTRUCTION(call
), /* call */
322 INSTRUCTION(jmpi
), /* jmpi */
323 INSTRUCTION_ILLEGAL(),
324 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbu */
325 INSTRUCTION(addi
), /* addi */
326 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stb */
327 INSTRUCTION(br
), /* br */
328 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldb */
329 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_GE
), /* cmpgei */
330 INSTRUCTION_ILLEGAL(),
331 INSTRUCTION_ILLEGAL(),
332 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhu */
333 INSTRUCTION(andi
), /* andi */
334 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sth */
335 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GE
), /* bge */
336 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldh */
337 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_LT
), /* cmplti */
338 INSTRUCTION_ILLEGAL(),
339 INSTRUCTION_ILLEGAL(),
340 INSTRUCTION_NOP(), /* initda */
341 INSTRUCTION(ori
), /* ori */
342 INSTRUCTION_FLG(gen_stx
, MO_UL
), /* stw */
343 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LT
), /* blt */
344 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldw */
345 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_NE
), /* cmpnei */
346 INSTRUCTION_ILLEGAL(),
347 INSTRUCTION_ILLEGAL(),
348 INSTRUCTION_NOP(), /* flushda */
349 INSTRUCTION(xori
), /* xori */
350 INSTRUCTION_ILLEGAL(),
351 INSTRUCTION_FLG(gen_bxx
, TCG_COND_NE
), /* bne */
352 INSTRUCTION_ILLEGAL(),
353 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_EQ
), /* cmpeqi */
354 INSTRUCTION_ILLEGAL(),
355 INSTRUCTION_ILLEGAL(),
356 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbuio */
357 INSTRUCTION(muli
), /* muli */
358 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stbio */
359 INSTRUCTION_FLG(gen_bxx
, TCG_COND_EQ
), /* beq */
360 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldbio */
361 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_GEU
), /* cmpgeui */
362 INSTRUCTION_ILLEGAL(),
363 INSTRUCTION_ILLEGAL(),
364 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhuio */
365 INSTRUCTION(andhi
), /* andhi */
366 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sthio */
367 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GEU
), /* bgeu */
368 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldhio */
369 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_LTU
), /* cmpltui */
370 INSTRUCTION_ILLEGAL(),
371 INSTRUCTION_UNIMPLEMENTED(), /* custom */
372 INSTRUCTION_NOP(), /* initd */
373 INSTRUCTION(orhi
), /* orhi */
374 INSTRUCTION_FLG(gen_stx
, MO_SL
), /* stwio */
375 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LTU
), /* bltu */
376 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldwio */
377 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
378 INSTRUCTION_ILLEGAL(),
379 INSTRUCTION_FLG(handle_r_type_instr
, 0), /* R-Type */
380 INSTRUCTION_NOP(), /* flushd */
381 INSTRUCTION(xorhi
), /* xorhi */
382 INSTRUCTION_ILLEGAL(),
383 INSTRUCTION_ILLEGAL(),
384 INSTRUCTION_ILLEGAL(),
388 * R-Type instructions
394 static void eret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
396 tcg_gen_mov_tl(dc
->cpu_R
[CR_STATUS
], dc
->cpu_R
[CR_ESTATUS
]);
397 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_EA
]);
399 dc
->is_jmp
= DISAS_JUMP
;
403 static void ret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
405 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_RA
]);
407 dc
->is_jmp
= DISAS_JUMP
;
411 static void bret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
413 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_BA
]);
415 dc
->is_jmp
= DISAS_JUMP
;
419 static void jmp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
423 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
425 dc
->is_jmp
= DISAS_JUMP
;
429 static void nextpc(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
433 if (likely(instr
.c
!= R_ZERO
)) {
434 tcg_gen_movi_tl(dc
->cpu_R
[instr
.c
], dc
->pc
+ 4);
442 static void callr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
446 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
447 tcg_gen_movi_tl(dc
->cpu_R
[R_RA
], dc
->pc
+ 4);
449 dc
->is_jmp
= DISAS_JUMP
;
453 static void rdctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
457 gen_check_supervisor(dc
);
459 switch (instr
.imm5
+ CR_BASE
) {
464 #if !defined(CONFIG_USER_ONLY)
465 if (likely(instr
.c
!= R_ZERO
)) {
466 tcg_gen_mov_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.imm5
+ CR_BASE
]);
468 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
469 gen_helper_mmu_read_debug(dc
->cpu_R
[instr
.c
], dc
->cpu_env
, tmp
);
470 tcg_temp_free_i32(tmp
);
478 if (likely(instr
.c
!= R_ZERO
)) {
479 tcg_gen_mov_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.imm5
+ CR_BASE
]);
486 static void wrctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
490 gen_check_supervisor(dc
);
492 switch (instr
.imm5
+ CR_BASE
) {
497 #if !defined(CONFIG_USER_ONLY)
498 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
499 gen_helper_mmu_write(dc
->cpu_env
, tmp
, load_gpr(dc
, instr
.a
));
500 tcg_temp_free_i32(tmp
);
506 tcg_gen_mov_tl(dc
->cpu_R
[instr
.imm5
+ CR_BASE
], load_gpr(dc
, instr
.a
));
510 /* If interrupts were enabled using WRCTL, trigger them. */
511 #if !defined(CONFIG_USER_ONLY)
512 if ((instr
.imm5
+ CR_BASE
) == CR_STATUS
) {
513 gen_helper_check_interrupts(dc
->cpu_env
);
518 /* Comparison instructions */
519 static void gen_cmpxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
522 if (likely(instr
.c
!= R_ZERO
)) {
523 tcg_gen_setcond_tl(flags
, dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.a
],
528 /* Math/logic instructions */
529 #define gen_r_math_logic(fname, insn, op3) \
530 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
532 R_TYPE(instr, (code)); \
533 if (likely(instr.c != R_ZERO)) { \
534 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), \
539 gen_r_math_logic(add
, add_tl
, load_gpr(dc
, instr
.b
))
540 gen_r_math_logic(sub
, sub_tl
, load_gpr(dc
, instr
.b
))
541 gen_r_math_logic(mul
, mul_tl
, load_gpr(dc
, instr
.b
))
543 gen_r_math_logic(and, and_tl
, load_gpr(dc
, instr
.b
))
544 gen_r_math_logic(or, or_tl
, load_gpr(dc
, instr
.b
))
545 gen_r_math_logic(xor, xor_tl
, load_gpr(dc
, instr
.b
))
546 gen_r_math_logic(nor
, nor_tl
, load_gpr(dc
, instr
.b
))
548 gen_r_math_logic(srai
, sari_tl
, instr
.imm5
)
549 gen_r_math_logic(srli
, shri_tl
, instr
.imm5
)
550 gen_r_math_logic(slli
, shli_tl
, instr
.imm5
)
551 gen_r_math_logic(roli
, rotli_tl
, instr
.imm5
)
553 #define gen_r_mul(fname, insn) \
554 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
556 R_TYPE(instr, (code)); \
557 if (likely(instr.c != R_ZERO)) { \
558 TCGv t0 = tcg_temp_new(); \
559 tcg_gen_##insn(t0, dc->cpu_R[instr.c], \
560 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
565 gen_r_mul(mulxss
, muls2_tl
)
566 gen_r_mul(mulxuu
, mulu2_tl
)
567 gen_r_mul(mulxsu
, mulsu2_tl
)
569 #define gen_r_shift_s(fname, insn) \
570 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
572 R_TYPE(instr, (code)); \
573 if (likely(instr.c != R_ZERO)) { \
574 TCGv t0 = tcg_temp_new(); \
575 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
576 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
581 gen_r_shift_s(sra
, sar_tl
)
582 gen_r_shift_s(srl
, shr_tl
)
583 gen_r_shift_s(sll
, shl_tl
)
584 gen_r_shift_s(rol
, rotl_tl
)
585 gen_r_shift_s(ror
, rotr_tl
)
587 static void divs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
589 R_TYPE(instr
, (code
));
591 /* Stores into R_ZERO are ignored */
592 if (unlikely(instr
.c
== R_ZERO
)) {
596 TCGv t0
= tcg_temp_new();
597 TCGv t1
= tcg_temp_new();
598 TCGv t2
= tcg_temp_new();
599 TCGv t3
= tcg_temp_new();
601 tcg_gen_ext32s_tl(t0
, load_gpr(dc
, instr
.a
));
602 tcg_gen_ext32s_tl(t1
, load_gpr(dc
, instr
.b
));
603 tcg_gen_setcondi_tl(TCG_COND_EQ
, t2
, t0
, INT_MIN
);
604 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, -1);
605 tcg_gen_and_tl(t2
, t2
, t3
);
606 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, 0);
607 tcg_gen_or_tl(t2
, t2
, t3
);
608 tcg_gen_movi_tl(t3
, 0);
609 tcg_gen_movcond_tl(TCG_COND_NE
, t1
, t2
, t3
, t2
, t1
);
610 tcg_gen_div_tl(dc
->cpu_R
[instr
.c
], t0
, t1
);
611 tcg_gen_ext32s_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.c
]);
619 static void divu(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
621 R_TYPE(instr
, (code
));
623 /* Stores into R_ZERO are ignored */
624 if (unlikely(instr
.c
== R_ZERO
)) {
628 TCGv t0
= tcg_temp_new();
629 TCGv t1
= tcg_temp_new();
630 TCGv t2
= tcg_const_tl(0);
631 TCGv t3
= tcg_const_tl(1);
633 tcg_gen_ext32u_tl(t0
, load_gpr(dc
, instr
.a
));
634 tcg_gen_ext32u_tl(t1
, load_gpr(dc
, instr
.b
));
635 tcg_gen_movcond_tl(TCG_COND_EQ
, t1
, t1
, t2
, t3
, t1
);
636 tcg_gen_divu_tl(dc
->cpu_R
[instr
.c
], t0
, t1
);
637 tcg_gen_ext32s_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.c
]);
645 static const Nios2Instruction r_type_instructions
[] = {
646 INSTRUCTION_ILLEGAL(),
647 INSTRUCTION(eret
), /* eret */
648 INSTRUCTION(roli
), /* roli */
649 INSTRUCTION(rol
), /* rol */
650 INSTRUCTION_NOP(), /* flushp */
651 INSTRUCTION(ret
), /* ret */
652 INSTRUCTION(nor
), /* nor */
653 INSTRUCTION(mulxuu
), /* mulxuu */
654 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GE
), /* cmpge */
655 INSTRUCTION(bret
), /* bret */
656 INSTRUCTION_ILLEGAL(),
657 INSTRUCTION(ror
), /* ror */
658 INSTRUCTION_NOP(), /* flushi */
659 INSTRUCTION(jmp
), /* jmp */
660 INSTRUCTION(and), /* and */
661 INSTRUCTION_ILLEGAL(),
662 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LT
), /* cmplt */
663 INSTRUCTION_ILLEGAL(),
664 INSTRUCTION(slli
), /* slli */
665 INSTRUCTION(sll
), /* sll */
666 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
667 INSTRUCTION_ILLEGAL(),
668 INSTRUCTION(or), /* or */
669 INSTRUCTION(mulxsu
), /* mulxsu */
670 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_NE
), /* cmpne */
671 INSTRUCTION_ILLEGAL(),
672 INSTRUCTION(srli
), /* srli */
673 INSTRUCTION(srl
), /* srl */
674 INSTRUCTION(nextpc
), /* nextpc */
675 INSTRUCTION(callr
), /* callr */
676 INSTRUCTION(xor), /* xor */
677 INSTRUCTION(mulxss
), /* mulxss */
678 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_EQ
), /* cmpeq */
679 INSTRUCTION_ILLEGAL(),
680 INSTRUCTION_ILLEGAL(),
681 INSTRUCTION_ILLEGAL(),
682 INSTRUCTION(divu
), /* divu */
683 INSTRUCTION(divs
), /* div */
684 INSTRUCTION(rdctl
), /* rdctl */
685 INSTRUCTION(mul
), /* mul */
686 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GEU
), /* cmpgeu */
687 INSTRUCTION_NOP(), /* initi */
688 INSTRUCTION_ILLEGAL(),
689 INSTRUCTION_ILLEGAL(),
690 INSTRUCTION_ILLEGAL(),
691 INSTRUCTION_FLG(gen_excp
, EXCP_TRAP
), /* trap */
692 INSTRUCTION(wrctl
), /* wrctl */
693 INSTRUCTION_ILLEGAL(),
694 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LTU
), /* cmpltu */
695 INSTRUCTION(add
), /* add */
696 INSTRUCTION_ILLEGAL(),
697 INSTRUCTION_ILLEGAL(),
698 INSTRUCTION_FLG(gen_excp
, EXCP_BREAK
), /* break */
699 INSTRUCTION_ILLEGAL(),
700 INSTRUCTION(nop
), /* nop */
701 INSTRUCTION_ILLEGAL(),
702 INSTRUCTION_ILLEGAL(),
703 INSTRUCTION(sub
), /* sub */
704 INSTRUCTION(srai
), /* srai */
705 INSTRUCTION(sra
), /* sra */
706 INSTRUCTION_ILLEGAL(),
707 INSTRUCTION_ILLEGAL(),
708 INSTRUCTION_ILLEGAL(),
709 INSTRUCTION_ILLEGAL(),
712 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
715 const Nios2Instruction
*instr
;
717 opx
= get_opxcode(code
);
718 if (unlikely(opx
>= ARRAY_SIZE(r_type_instructions
))) {
722 instr
= &r_type_instructions
[opx
];
723 instr
->handler(dc
, code
, instr
->flags
);
728 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
731 static void handle_instruction(DisasContext
*dc
, CPUNios2State
*env
)
735 const Nios2Instruction
*instr
;
736 #if defined(CONFIG_USER_ONLY)
737 /* FIXME: Is this needed ? */
738 if (dc
->pc
>= 0x1000 && dc
->pc
< 0x2000) {
739 env
->regs
[R_PC
] = dc
->pc
;
740 t_gen_helper_raise_exception(dc
, 0xaa);
744 code
= cpu_ldl_code(env
, dc
->pc
);
745 op
= get_opcode(code
);
747 if (unlikely(op
>= ARRAY_SIZE(i_type_instructions
))) {
751 TCGV_UNUSED_I32(dc
->zero
);
753 instr
= &i_type_instructions
[op
];
754 instr
->handler(dc
, code
, instr
->flags
);
756 if (!TCGV_IS_UNUSED_I32(dc
->zero
)) {
757 tcg_temp_free(dc
->zero
);
763 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
766 static const char * const regnames
[] = {
767 "zero", "at", "r2", "r3",
768 "r4", "r5", "r6", "r7",
769 "r8", "r9", "r10", "r11",
770 "r12", "r13", "r14", "r15",
771 "r16", "r17", "r18", "r19",
772 "r20", "r21", "r22", "r23",
773 "et", "bt", "gp", "sp",
774 "fp", "ea", "ba", "ra",
775 "status", "estatus", "bstatus", "ienable",
776 "ipending", "cpuid", "reserved0", "exception",
777 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
778 "badaddr", "config", "mpubase", "mpuacc",
779 "reserved2", "reserved3", "reserved4", "reserved5",
780 "reserved6", "reserved7", "reserved8", "reserved9",
781 "reserved10", "reserved11", "reserved12", "reserved13",
782 "reserved14", "reserved15", "reserved16", "reserved17",
786 static TCGv_ptr cpu_env
;
787 static TCGv cpu_R
[NUM_CORE_REGS
];
789 #include "exec/gen-icount.h"
791 static void gen_exception(DisasContext
*dc
, uint32_t excp
)
793 TCGv_i32 tmp
= tcg_const_i32(excp
);
795 tcg_gen_movi_tl(cpu_R
[R_PC
], dc
->pc
);
796 gen_helper_raise_exception(cpu_env
, tmp
);
797 tcg_temp_free_i32(tmp
);
798 dc
->is_jmp
= DISAS_UPDATE
;
801 /* generate intermediate code for basic block 'tb'. */
802 void gen_intermediate_code(CPUState
*cs
, TranslationBlock
*tb
)
804 CPUNios2State
*env
= cs
->env_ptr
;
805 DisasContext dc1
, *dc
= &dc1
;
810 dc
->cpu_env
= cpu_env
;
812 dc
->is_jmp
= DISAS_NEXT
;
815 dc
->mem_idx
= cpu_mmu_index(env
, false);
816 dc
->singlestep_enabled
= cs
->singlestep_enabled
;
818 /* Set up instruction counts */
820 if (cs
->singlestep_enabled
|| singlestep
) {
823 int page_insns
= (TARGET_PAGE_SIZE
- (tb
->pc
& TARGET_PAGE_MASK
)) / 4;
824 max_insns
= tb
->cflags
& CF_COUNT_MASK
;
825 if (max_insns
== 0) {
826 max_insns
= CF_COUNT_MASK
;
828 if (max_insns
> page_insns
) {
829 max_insns
= page_insns
;
831 if (max_insns
> TCG_MAX_INSNS
) {
832 max_insns
= TCG_MAX_INSNS
;
838 tcg_gen_insn_start(dc
->pc
);
841 if (unlikely(cpu_breakpoint_test(cs
, dc
->pc
, BP_ANY
))) {
842 gen_exception(dc
, EXCP_DEBUG
);
843 /* The address covered by the breakpoint must be included in
844 [tb->pc, tb->pc + tb->size) in order to for it to be
845 properly cleared -- thus we increment the PC here so that
846 the logic setting tb->size below does the right thing. */
851 if (num_insns
== max_insns
&& (tb
->cflags
& CF_LAST_IO
)) {
855 /* Decode an instruction */
856 handle_instruction(dc
, env
);
860 /* Translation stops when a conditional branch is encountered.
861 * Otherwise the subsequent code could get translated several times.
862 * Also stop translation when a page boundary is reached. This
863 * ensures prefetch aborts occur at the right place. */
864 } while (!dc
->is_jmp
&&
865 !tcg_op_buf_full() &&
866 num_insns
< max_insns
);
868 if (tb
->cflags
& CF_LAST_IO
) {
872 /* Indicate where the next block should start */
873 switch (dc
->is_jmp
) {
875 /* Save the current PC back into the CPU register */
876 tcg_gen_movi_tl(cpu_R
[R_PC
], dc
->pc
);
883 /* The jump will already have updated the PC register */
888 /* nothing more to generate */
892 /* End off the block */
893 gen_tb_end(tb
, num_insns
);
895 /* Mark instruction starts for the final generated instruction */
896 tb
->size
= dc
->pc
- tb
->pc
;
897 tb
->icount
= num_insns
;
900 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)
901 && qemu_log_in_addr_range(tb
->pc
)) {
903 qemu_log("IN: %s\n", lookup_symbol(tb
->pc
));
904 log_target_disas(cs
, tb
->pc
, dc
->pc
- tb
->pc
, 0);
911 void nios2_cpu_dump_state(CPUState
*cs
, FILE *f
, fprintf_function cpu_fprintf
,
914 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
915 CPUNios2State
*env
= &cpu
->env
;
922 cpu_fprintf(f
, "IN: PC=%x %s\n",
923 env
->regs
[R_PC
], lookup_symbol(env
->regs
[R_PC
]));
925 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
926 cpu_fprintf(f
, "%9s=%8.8x ", regnames
[i
], env
->regs
[i
]);
927 if ((i
+ 1) % 4 == 0) {
928 cpu_fprintf(f
, "\n");
931 #if !defined(CONFIG_USER_ONLY)
932 cpu_fprintf(f
, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
933 env
->mmu
.pteaddr_wr
& CR_PTEADDR_VPN_MASK
,
934 (env
->mmu
.tlbmisc_wr
& CR_TLBMISC_PID_MASK
) >> 4,
937 cpu_fprintf(f
, "\n\n");
940 void nios2_tcg_init(void)
944 cpu_env
= tcg_global_reg_new_ptr(TCG_AREG0
, "env");
946 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
947 cpu_R
[i
] = tcg_global_mem_new(cpu_env
,
948 offsetof(CPUNios2State
, regs
[i
]),
953 void restore_state_to_opc(CPUNios2State
*env
, TranslationBlock
*tb
,
956 env
->regs
[R_PC
] = data
[0];