unicore32: abort when entering "x 0" on the monitor
[qemu/ar7.git] / target / nios2 / translate.c
blob8b97d6585f0016622fe5b11538b13b2fd7d38199
1 /*
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 "cpu.h"
25 #include "tcg-op.h"
26 #include "exec/exec-all.h"
27 #include "disas/disas.h"
28 #include "exec/helper-proto.h"
29 #include "exec/helper-gen.h"
30 #include "exec/log.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) \
48 struct { \
49 uint8_t op; \
50 union { \
51 uint16_t u; \
52 int16_t s; \
53 } imm16; \
54 uint8_t b; \
55 uint8_t a; \
56 } (instr) = { \
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) \
65 struct { \
66 uint8_t op; \
67 uint8_t imm5; \
68 uint8_t opx; \
69 uint8_t c; \
70 uint8_t b; \
71 uint8_t a; \
72 } (instr) = { \
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) \
83 struct { \
84 uint8_t op; \
85 uint32_t imm26; \
86 } (instr) = { \
87 .op = extract32((code), 0, 6), \
88 .imm26 = extract32((code), 6, 26), \
91 typedef struct DisasContext {
92 TCGv_ptr cpu_env;
93 TCGv *cpu_R;
94 TCGv_i32 zero;
95 int is_jmp;
96 target_ulong pc;
97 TranslationBlock *tb;
98 int mem_idx;
99 bool singlestep_enabled;
100 } DisasContext;
102 typedef struct Nios2Instruction {
103 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
104 uint32_t flags;
105 } Nios2Instruction;
107 static uint8_t get_opcode(uint32_t code)
109 I_TYPE(instr, code);
110 return instr.op;
113 static uint8_t get_opxcode(uint32_t code)
115 R_TYPE(instr, code);
116 return instr.opx;
119 static TCGv load_zero(DisasContext *dc)
121 if (TCGV_IS_UNUSED_I32(dc->zero)) {
122 dc->zero = tcg_const_i32(0);
124 return dc->zero;
127 static TCGv load_gpr(DisasContext *dc, uint8_t reg)
129 if (likely(reg != R_ZERO)) {
130 return dc->cpu_R[reg];
131 } else {
132 return load_zero(dc);
136 static void t_gen_helper_raise_exception(DisasContext *dc,
137 uint32_t index)
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)) {
150 return false;
153 #ifndef CONFIG_USER_ONLY
154 return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
155 #else
156 return true;
157 #endif
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)) {
165 tcg_gen_goto_tb(n);
166 tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
167 tcg_gen_exit_tb((uintptr_t)tb + n);
168 } else {
169 tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
170 tcg_gen_exit_tb(0);
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)
201 J_TYPE(instr, code);
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)
218 I_TYPE(instr, code);
220 TCGv addr = tcg_temp_new();
221 TCGv data;
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
227 * the Nios2 CPU.
229 if (likely(instr.b != R_ZERO)) {
230 data = dc->cpu_R[instr.b];
231 } else {
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)) {
239 tcg_temp_free(data);
242 tcg_temp_free(addr);
245 /* Store instructions */
246 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
248 I_TYPE(instr, code);
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);
254 tcg_temp_free(addr);
257 /* Branch instructions */
258 static void br(DisasContext *dc, uint32_t code, uint32_t flags)
260 I_TYPE(instr, code);
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)
268 I_TYPE(instr, code);
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);
273 gen_set_label(l1);
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], \
284 (op3)); \
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 */ \
296 return; \
297 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
298 tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0); \
299 } else { \
300 tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
301 (op3)); \
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,
318 uint32_t flags);
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
391 * status <- estatus
392 * PC <- ea
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;
402 /* PC <- ra */
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;
410 /* PC <- ba */
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;
418 /* PC <- rA */
419 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
421 R_TYPE(instr, code);
423 tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
425 dc->is_jmp = DISAS_JUMP;
428 /* rC <- PC + 4 */
429 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
431 R_TYPE(instr, code);
433 if (likely(instr.c != R_ZERO)) {
434 tcg_gen_movi_tl(dc->cpu_R[instr.c], dc->pc + 4);
439 * ra <- PC + 4
440 * PC <- rA
442 static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
444 R_TYPE(instr, code);
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;
452 /* rC <- ctlN */
453 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
455 R_TYPE(instr, code);
457 gen_check_supervisor(dc);
459 switch (instr.imm5 + CR_BASE) {
460 case CR_PTEADDR:
461 case CR_TLBACC:
462 case CR_TLBMISC:
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]);
467 #ifdef DEBUG_MMU
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);
471 #endif
473 #endif
474 break;
477 default:
478 if (likely(instr.c != R_ZERO)) {
479 tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
481 break;
485 /* ctlN <- rA */
486 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
488 R_TYPE(instr, code);
490 gen_check_supervisor(dc);
492 switch (instr.imm5 + CR_BASE) {
493 case CR_PTEADDR:
494 case CR_TLBACC:
495 case CR_TLBMISC:
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);
501 #endif
502 break;
505 default:
506 tcg_gen_mov_tl(dc->cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a));
507 break;
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);
515 #endif
518 /* Comparison instructions */
519 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
521 R_TYPE(instr, code);
522 if (likely(instr.c != R_ZERO)) {
523 tcg_gen_setcond_tl(flags, dc->cpu_R[instr.c], dc->cpu_R[instr.a],
524 dc->cpu_R[instr.b]);
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), \
535 (op3)); \
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)); \
561 tcg_temp_free(t0); \
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); \
577 tcg_temp_free(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)) {
593 return;
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]);
613 tcg_temp_free(t3);
614 tcg_temp_free(t2);
615 tcg_temp_free(t1);
616 tcg_temp_free(t0);
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)) {
625 return;
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]);
639 tcg_temp_free(t3);
640 tcg_temp_free(t2);
641 tcg_temp_free(t1);
642 tcg_temp_free(t0);
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)
714 uint8_t opx;
715 const Nios2Instruction *instr;
717 opx = get_opxcode(code);
718 if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
719 goto illegal_op;
722 instr = &r_type_instructions[opx];
723 instr->handler(dc, code, instr->flags);
725 return;
727 illegal_op:
728 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
731 static void handle_instruction(DisasContext *dc, CPUNios2State *env)
733 uint32_t code;
734 uint8_t op;
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);
741 return;
743 #endif
744 code = cpu_ldl_code(env, dc->pc);
745 op = get_opcode(code);
747 if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
748 goto illegal_op;
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);
760 return;
762 illegal_op:
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",
783 "rpc"
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;
806 int num_insns;
807 int max_insns;
809 /* Initialize DC */
810 dc->cpu_env = cpu_env;
811 dc->cpu_R = cpu_R;
812 dc->is_jmp = DISAS_NEXT;
813 dc->pc = tb->pc;
814 dc->tb = tb;
815 dc->mem_idx = cpu_mmu_index(env, false);
816 dc->singlestep_enabled = cs->singlestep_enabled;
818 /* Set up instruction counts */
819 num_insns = 0;
820 if (cs->singlestep_enabled || singlestep) {
821 max_insns = 1;
822 } else {
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;
836 gen_tb_start(tb);
837 do {
838 tcg_gen_insn_start(dc->pc);
839 num_insns++;
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. */
847 dc->pc += 4;
848 break;
851 if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
852 gen_io_start();
855 /* Decode an instruction */
856 handle_instruction(dc, env);
858 dc->pc += 4;
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) {
869 gen_io_end();
872 /* Indicate where the next block should start */
873 switch (dc->is_jmp) {
874 case DISAS_NEXT:
875 /* Save the current PC back into the CPU register */
876 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
877 tcg_gen_exit_tb(0);
878 break;
880 default:
881 case DISAS_JUMP:
882 case DISAS_UPDATE:
883 /* The jump will already have updated the PC register */
884 tcg_gen_exit_tb(0);
885 break;
887 case DISAS_TB_JUMP:
888 /* nothing more to generate */
889 break;
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;
899 #ifdef DEBUG_DISAS
900 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
901 && qemu_log_in_addr_range(tb->pc)) {
902 qemu_log_lock();
903 qemu_log("IN: %s\n", lookup_symbol(tb->pc));
904 log_target_disas(cs, tb->pc, dc->pc - tb->pc, 0);
905 qemu_log("\n");
906 qemu_log_unlock();
908 #endif
911 void nios2_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
912 int flags)
914 Nios2CPU *cpu = NIOS2_CPU(cs);
915 CPUNios2State *env = &cpu->env;
916 int i;
918 if (!env || !f) {
919 return;
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,
935 env->mmu.tlbacc_wr);
936 #endif
937 cpu_fprintf(f, "\n\n");
940 void nios2_tcg_init(void)
942 int i;
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]),
949 regnames[i]);
953 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
954 target_ulong *data)
956 env->regs[R_PC] = data[0];