tests/docker: Use --arch-only when building Debian cross image
[qemu/ar7.git] / target / nios2 / translate.c
blob9824544eb37c9a94d18081a566d14c0bf4ce8bda
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 "qemu/osdep.h"
25 #include "cpu.h"
26 #include "tcg/tcg-op.h"
27 #include "exec/exec-all.h"
28 #include "disas/disas.h"
29 #include "exec/helper-proto.h"
30 #include "exec/helper-gen.h"
31 #include "exec/log.h"
32 #include "exec/cpu_ldst.h"
33 #include "exec/translator.h"
34 #include "qemu/qemu-print.h"
35 #include "exec/gen-icount.h"
37 /* is_jmp field values */
38 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
39 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
40 #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
42 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
43 #define INSTRUCTION(func) \
44 INSTRUCTION_FLG(func, 0)
45 #define INSTRUCTION_NOP() \
46 INSTRUCTION_FLG(nop, 0)
47 #define INSTRUCTION_UNIMPLEMENTED() \
48 INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
49 #define INSTRUCTION_ILLEGAL() \
50 INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
52 /* Special R-Type instruction opcode */
53 #define INSN_R_TYPE 0x3A
55 /* I-Type instruction parsing */
56 #define I_TYPE(instr, code) \
57 struct { \
58 uint8_t op; \
59 union { \
60 uint16_t u; \
61 int16_t s; \
62 } imm16; \
63 uint8_t b; \
64 uint8_t a; \
65 } (instr) = { \
66 .op = extract32((code), 0, 6), \
67 .imm16.u = extract32((code), 6, 16), \
68 .b = extract32((code), 22, 5), \
69 .a = extract32((code), 27, 5), \
72 /* R-Type instruction parsing */
73 #define R_TYPE(instr, code) \
74 struct { \
75 uint8_t op; \
76 uint8_t imm5; \
77 uint8_t opx; \
78 uint8_t c; \
79 uint8_t b; \
80 uint8_t a; \
81 } (instr) = { \
82 .op = extract32((code), 0, 6), \
83 .imm5 = extract32((code), 6, 5), \
84 .opx = extract32((code), 11, 6), \
85 .c = extract32((code), 17, 5), \
86 .b = extract32((code), 22, 5), \
87 .a = extract32((code), 27, 5), \
90 /* J-Type instruction parsing */
91 #define J_TYPE(instr, code) \
92 struct { \
93 uint8_t op; \
94 uint32_t imm26; \
95 } (instr) = { \
96 .op = extract32((code), 0, 6), \
97 .imm26 = extract32((code), 6, 26), \
100 typedef struct DisasContext {
101 TCGv_ptr cpu_env;
102 TCGv *cpu_R;
103 TCGv_i32 zero;
104 int is_jmp;
105 target_ulong pc;
106 TranslationBlock *tb;
107 int mem_idx;
108 bool singlestep_enabled;
109 } DisasContext;
111 typedef struct Nios2Instruction {
112 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
113 uint32_t flags;
114 } Nios2Instruction;
116 static uint8_t get_opcode(uint32_t code)
118 I_TYPE(instr, code);
119 return instr.op;
122 static uint8_t get_opxcode(uint32_t code)
124 R_TYPE(instr, code);
125 return instr.opx;
128 static TCGv load_zero(DisasContext *dc)
130 if (!dc->zero) {
131 dc->zero = tcg_const_i32(0);
133 return dc->zero;
136 static TCGv load_gpr(DisasContext *dc, uint8_t reg)
138 if (likely(reg != R_ZERO)) {
139 return dc->cpu_R[reg];
140 } else {
141 return load_zero(dc);
145 static void t_gen_helper_raise_exception(DisasContext *dc,
146 uint32_t index)
148 TCGv_i32 tmp = tcg_const_i32(index);
150 tcg_gen_movi_tl(dc->cpu_R[R_PC], dc->pc);
151 gen_helper_raise_exception(dc->cpu_env, tmp);
152 tcg_temp_free_i32(tmp);
153 dc->is_jmp = DISAS_NORETURN;
156 static bool use_goto_tb(DisasContext *dc, uint32_t dest)
158 if (unlikely(dc->singlestep_enabled)) {
159 return false;
162 #ifndef CONFIG_USER_ONLY
163 return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
164 #else
165 return true;
166 #endif
169 static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
171 TranslationBlock *tb = dc->tb;
173 if (use_goto_tb(dc, dest)) {
174 tcg_gen_goto_tb(n);
175 tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
176 tcg_gen_exit_tb(tb, n);
177 } else {
178 tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
179 tcg_gen_exit_tb(NULL, 0);
183 static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
185 t_gen_helper_raise_exception(dc, flags);
188 static void gen_check_supervisor(DisasContext *dc)
190 if (dc->tb->flags & CR_STATUS_U) {
191 /* CPU in user mode, privileged instruction called, stop. */
192 t_gen_helper_raise_exception(dc, EXCP_SUPERI);
197 * Used as a placeholder for all instructions which do not have
198 * an effect on the simulator (e.g. flush, sync)
200 static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
202 /* Nothing to do here */
206 * J-Type instructions
208 static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
210 J_TYPE(instr, code);
211 gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
212 dc->is_jmp = DISAS_TB_JUMP;
215 static void call(DisasContext *dc, uint32_t code, uint32_t flags)
217 tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
218 jmpi(dc, code, flags);
222 * I-Type instructions
224 /* Load instructions */
225 static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
227 I_TYPE(instr, code);
229 TCGv addr = tcg_temp_new();
230 TCGv data;
233 * WARNING: Loads into R_ZERO are ignored, but we must generate the
234 * memory access itself to emulate the CPU precisely. Load
235 * from a protected page to R_ZERO will cause SIGSEGV on
236 * the Nios2 CPU.
238 if (likely(instr.b != R_ZERO)) {
239 data = dc->cpu_R[instr.b];
240 } else {
241 data = tcg_temp_new();
244 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
245 tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
247 if (unlikely(instr.b == R_ZERO)) {
248 tcg_temp_free(data);
251 tcg_temp_free(addr);
254 /* Store instructions */
255 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
257 I_TYPE(instr, code);
258 TCGv val = load_gpr(dc, instr.b);
260 TCGv addr = tcg_temp_new();
261 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
262 tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
263 tcg_temp_free(addr);
266 /* Branch instructions */
267 static void br(DisasContext *dc, uint32_t code, uint32_t flags)
269 I_TYPE(instr, code);
271 gen_goto_tb(dc, 0, dc->pc + 4 + (instr.imm16.s & -4));
272 dc->is_jmp = DISAS_TB_JUMP;
275 static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
277 I_TYPE(instr, code);
279 TCGLabel *l1 = gen_new_label();
280 tcg_gen_brcond_tl(flags, dc->cpu_R[instr.a], dc->cpu_R[instr.b], l1);
281 gen_goto_tb(dc, 0, dc->pc + 4);
282 gen_set_label(l1);
283 gen_goto_tb(dc, 1, dc->pc + 4 + (instr.imm16.s & -4));
284 dc->is_jmp = DISAS_TB_JUMP;
287 /* Comparison instructions */
288 #define gen_i_cmpxx(fname, op3) \
289 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
291 I_TYPE(instr, (code)); \
292 tcg_gen_setcondi_tl(flags, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
293 (op3)); \
296 gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s)
297 gen_i_cmpxx(gen_cmpxxui, instr.imm16.u)
299 /* Math/logic instructions */
300 #define gen_i_math_logic(fname, insn, resimm, op3) \
301 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
303 I_TYPE(instr, (code)); \
304 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
305 return; \
306 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
307 tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0); \
308 } else { \
309 tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
310 (op3)); \
314 gen_i_math_logic(addi, addi, 1, instr.imm16.s)
315 gen_i_math_logic(muli, muli, 0, instr.imm16.s)
317 gen_i_math_logic(andi, andi, 0, instr.imm16.u)
318 gen_i_math_logic(ori, ori, 1, instr.imm16.u)
319 gen_i_math_logic(xori, xori, 1, instr.imm16.u)
321 gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16)
322 gen_i_math_logic(orhi , ori, 1, instr.imm16.u << 16)
323 gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16)
325 /* Prototype only, defined below */
326 static void handle_r_type_instr(DisasContext *dc, uint32_t code,
327 uint32_t flags);
329 static const Nios2Instruction i_type_instructions[] = {
330 INSTRUCTION(call), /* call */
331 INSTRUCTION(jmpi), /* jmpi */
332 INSTRUCTION_ILLEGAL(),
333 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */
334 INSTRUCTION(addi), /* addi */
335 INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */
336 INSTRUCTION(br), /* br */
337 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */
338 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */
339 INSTRUCTION_ILLEGAL(),
340 INSTRUCTION_ILLEGAL(),
341 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhu */
342 INSTRUCTION(andi), /* andi */
343 INSTRUCTION_FLG(gen_stx, MO_UW), /* sth */
344 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */
345 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldh */
346 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */
347 INSTRUCTION_ILLEGAL(),
348 INSTRUCTION_ILLEGAL(),
349 INSTRUCTION_NOP(), /* initda */
350 INSTRUCTION(ori), /* ori */
351 INSTRUCTION_FLG(gen_stx, MO_UL), /* stw */
352 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */
353 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldw */
354 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */
355 INSTRUCTION_ILLEGAL(),
356 INSTRUCTION_ILLEGAL(),
357 INSTRUCTION_NOP(), /* flushda */
358 INSTRUCTION(xori), /* xori */
359 INSTRUCTION_ILLEGAL(),
360 INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */
361 INSTRUCTION_ILLEGAL(),
362 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */
363 INSTRUCTION_ILLEGAL(),
364 INSTRUCTION_ILLEGAL(),
365 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */
366 INSTRUCTION(muli), /* muli */
367 INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */
368 INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */
369 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */
370 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */
371 INSTRUCTION_ILLEGAL(),
372 INSTRUCTION_ILLEGAL(),
373 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhuio */
374 INSTRUCTION(andhi), /* andhi */
375 INSTRUCTION_FLG(gen_stx, MO_UW), /* sthio */
376 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */
377 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldhio */
378 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */
379 INSTRUCTION_ILLEGAL(),
380 INSTRUCTION_UNIMPLEMENTED(), /* custom */
381 INSTRUCTION_NOP(), /* initd */
382 INSTRUCTION(orhi), /* orhi */
383 INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */
384 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */
385 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */
386 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
387 INSTRUCTION_ILLEGAL(),
388 INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */
389 INSTRUCTION_NOP(), /* flushd */
390 INSTRUCTION(xorhi), /* xorhi */
391 INSTRUCTION_ILLEGAL(),
392 INSTRUCTION_ILLEGAL(),
393 INSTRUCTION_ILLEGAL(),
397 * R-Type instructions
400 * status <- estatus
401 * PC <- ea
403 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
405 tcg_gen_mov_tl(dc->cpu_R[CR_STATUS], dc->cpu_R[CR_ESTATUS]);
406 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_EA]);
408 dc->is_jmp = DISAS_JUMP;
411 /* PC <- ra */
412 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
414 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_RA]);
416 dc->is_jmp = DISAS_JUMP;
419 /* PC <- ba */
420 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
422 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_BA]);
424 dc->is_jmp = DISAS_JUMP;
427 /* PC <- rA */
428 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
430 R_TYPE(instr, code);
432 tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
434 dc->is_jmp = DISAS_JUMP;
437 /* rC <- PC + 4 */
438 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
440 R_TYPE(instr, code);
442 if (likely(instr.c != R_ZERO)) {
443 tcg_gen_movi_tl(dc->cpu_R[instr.c], dc->pc + 4);
448 * ra <- PC + 4
449 * PC <- rA
451 static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
453 R_TYPE(instr, code);
455 tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
456 tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
458 dc->is_jmp = DISAS_JUMP;
461 /* rC <- ctlN */
462 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
464 R_TYPE(instr, code);
466 gen_check_supervisor(dc);
468 switch (instr.imm5 + CR_BASE) {
469 case CR_PTEADDR:
470 case CR_TLBACC:
471 case CR_TLBMISC:
473 #if !defined(CONFIG_USER_ONLY)
474 if (likely(instr.c != R_ZERO)) {
475 tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
476 #ifdef DEBUG_MMU
477 TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
478 gen_helper_mmu_read_debug(dc->cpu_R[instr.c], dc->cpu_env, tmp);
479 tcg_temp_free_i32(tmp);
480 #endif
482 #endif
483 break;
486 default:
487 if (likely(instr.c != R_ZERO)) {
488 tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
490 break;
494 /* ctlN <- rA */
495 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
497 R_TYPE(instr, code);
499 gen_check_supervisor(dc);
501 switch (instr.imm5 + CR_BASE) {
502 case CR_PTEADDR:
503 case CR_TLBACC:
504 case CR_TLBMISC:
506 #if !defined(CONFIG_USER_ONLY)
507 TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
508 gen_helper_mmu_write(dc->cpu_env, tmp, load_gpr(dc, instr.a));
509 tcg_temp_free_i32(tmp);
510 #endif
511 break;
514 default:
515 tcg_gen_mov_tl(dc->cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a));
516 break;
519 /* If interrupts were enabled using WRCTL, trigger them. */
520 #if !defined(CONFIG_USER_ONLY)
521 if ((instr.imm5 + CR_BASE) == CR_STATUS) {
522 if (tb_cflags(dc->tb) & CF_USE_ICOUNT) {
523 gen_io_start();
525 gen_helper_check_interrupts(dc->cpu_env);
526 dc->is_jmp = DISAS_UPDATE;
528 #endif
531 /* Comparison instructions */
532 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
534 R_TYPE(instr, code);
535 if (likely(instr.c != R_ZERO)) {
536 tcg_gen_setcond_tl(flags, dc->cpu_R[instr.c], dc->cpu_R[instr.a],
537 dc->cpu_R[instr.b]);
541 /* Math/logic instructions */
542 #define gen_r_math_logic(fname, insn, op3) \
543 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
545 R_TYPE(instr, (code)); \
546 if (likely(instr.c != R_ZERO)) { \
547 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), \
548 (op3)); \
552 gen_r_math_logic(add, add_tl, load_gpr(dc, instr.b))
553 gen_r_math_logic(sub, sub_tl, load_gpr(dc, instr.b))
554 gen_r_math_logic(mul, mul_tl, load_gpr(dc, instr.b))
556 gen_r_math_logic(and, and_tl, load_gpr(dc, instr.b))
557 gen_r_math_logic(or, or_tl, load_gpr(dc, instr.b))
558 gen_r_math_logic(xor, xor_tl, load_gpr(dc, instr.b))
559 gen_r_math_logic(nor, nor_tl, load_gpr(dc, instr.b))
561 gen_r_math_logic(srai, sari_tl, instr.imm5)
562 gen_r_math_logic(srli, shri_tl, instr.imm5)
563 gen_r_math_logic(slli, shli_tl, instr.imm5)
564 gen_r_math_logic(roli, rotli_tl, instr.imm5)
566 #define gen_r_mul(fname, insn) \
567 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
569 R_TYPE(instr, (code)); \
570 if (likely(instr.c != R_ZERO)) { \
571 TCGv t0 = tcg_temp_new(); \
572 tcg_gen_##insn(t0, dc->cpu_R[instr.c], \
573 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
574 tcg_temp_free(t0); \
578 gen_r_mul(mulxss, muls2_tl)
579 gen_r_mul(mulxuu, mulu2_tl)
580 gen_r_mul(mulxsu, mulsu2_tl)
582 #define gen_r_shift_s(fname, insn) \
583 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
585 R_TYPE(instr, (code)); \
586 if (likely(instr.c != R_ZERO)) { \
587 TCGv t0 = tcg_temp_new(); \
588 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
589 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
590 tcg_temp_free(t0); \
594 gen_r_shift_s(sra, sar_tl)
595 gen_r_shift_s(srl, shr_tl)
596 gen_r_shift_s(sll, shl_tl)
597 gen_r_shift_s(rol, rotl_tl)
598 gen_r_shift_s(ror, rotr_tl)
600 static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
602 R_TYPE(instr, (code));
604 /* Stores into R_ZERO are ignored */
605 if (unlikely(instr.c == R_ZERO)) {
606 return;
609 TCGv t0 = tcg_temp_new();
610 TCGv t1 = tcg_temp_new();
611 TCGv t2 = tcg_temp_new();
612 TCGv t3 = tcg_temp_new();
614 tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a));
615 tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b));
616 tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
617 tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
618 tcg_gen_and_tl(t2, t2, t3);
619 tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
620 tcg_gen_or_tl(t2, t2, t3);
621 tcg_gen_movi_tl(t3, 0);
622 tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
623 tcg_gen_div_tl(dc->cpu_R[instr.c], t0, t1);
624 tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
626 tcg_temp_free(t3);
627 tcg_temp_free(t2);
628 tcg_temp_free(t1);
629 tcg_temp_free(t0);
632 static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
634 R_TYPE(instr, (code));
636 /* Stores into R_ZERO are ignored */
637 if (unlikely(instr.c == R_ZERO)) {
638 return;
641 TCGv t0 = tcg_temp_new();
642 TCGv t1 = tcg_temp_new();
643 TCGv t2 = tcg_const_tl(0);
644 TCGv t3 = tcg_const_tl(1);
646 tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
647 tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
648 tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
649 tcg_gen_divu_tl(dc->cpu_R[instr.c], t0, t1);
650 tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
652 tcg_temp_free(t3);
653 tcg_temp_free(t2);
654 tcg_temp_free(t1);
655 tcg_temp_free(t0);
658 static const Nios2Instruction r_type_instructions[] = {
659 INSTRUCTION_ILLEGAL(),
660 INSTRUCTION(eret), /* eret */
661 INSTRUCTION(roli), /* roli */
662 INSTRUCTION(rol), /* rol */
663 INSTRUCTION_NOP(), /* flushp */
664 INSTRUCTION(ret), /* ret */
665 INSTRUCTION(nor), /* nor */
666 INSTRUCTION(mulxuu), /* mulxuu */
667 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */
668 INSTRUCTION(bret), /* bret */
669 INSTRUCTION_ILLEGAL(),
670 INSTRUCTION(ror), /* ror */
671 INSTRUCTION_NOP(), /* flushi */
672 INSTRUCTION(jmp), /* jmp */
673 INSTRUCTION(and), /* and */
674 INSTRUCTION_ILLEGAL(),
675 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */
676 INSTRUCTION_ILLEGAL(),
677 INSTRUCTION(slli), /* slli */
678 INSTRUCTION(sll), /* sll */
679 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
680 INSTRUCTION_ILLEGAL(),
681 INSTRUCTION(or), /* or */
682 INSTRUCTION(mulxsu), /* mulxsu */
683 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */
684 INSTRUCTION_ILLEGAL(),
685 INSTRUCTION(srli), /* srli */
686 INSTRUCTION(srl), /* srl */
687 INSTRUCTION(nextpc), /* nextpc */
688 INSTRUCTION(callr), /* callr */
689 INSTRUCTION(xor), /* xor */
690 INSTRUCTION(mulxss), /* mulxss */
691 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */
692 INSTRUCTION_ILLEGAL(),
693 INSTRUCTION_ILLEGAL(),
694 INSTRUCTION_ILLEGAL(),
695 INSTRUCTION(divu), /* divu */
696 INSTRUCTION(divs), /* div */
697 INSTRUCTION(rdctl), /* rdctl */
698 INSTRUCTION(mul), /* mul */
699 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */
700 INSTRUCTION_NOP(), /* initi */
701 INSTRUCTION_ILLEGAL(),
702 INSTRUCTION_ILLEGAL(),
703 INSTRUCTION_ILLEGAL(),
704 INSTRUCTION_FLG(gen_excp, EXCP_TRAP), /* trap */
705 INSTRUCTION(wrctl), /* wrctl */
706 INSTRUCTION_ILLEGAL(),
707 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */
708 INSTRUCTION(add), /* add */
709 INSTRUCTION_ILLEGAL(),
710 INSTRUCTION_ILLEGAL(),
711 INSTRUCTION_FLG(gen_excp, EXCP_BREAK), /* break */
712 INSTRUCTION_ILLEGAL(),
713 INSTRUCTION(nop), /* nop */
714 INSTRUCTION_ILLEGAL(),
715 INSTRUCTION_ILLEGAL(),
716 INSTRUCTION(sub), /* sub */
717 INSTRUCTION(srai), /* srai */
718 INSTRUCTION(sra), /* sra */
719 INSTRUCTION_ILLEGAL(),
720 INSTRUCTION_ILLEGAL(),
721 INSTRUCTION_ILLEGAL(),
722 INSTRUCTION_ILLEGAL(),
725 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
727 uint8_t opx;
728 const Nios2Instruction *instr;
730 opx = get_opxcode(code);
731 if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
732 goto illegal_op;
735 instr = &r_type_instructions[opx];
736 instr->handler(dc, code, instr->flags);
738 return;
740 illegal_op:
741 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
744 static void handle_instruction(DisasContext *dc, CPUNios2State *env)
746 uint32_t code;
747 uint8_t op;
748 const Nios2Instruction *instr;
749 #if defined(CONFIG_USER_ONLY)
750 /* FIXME: Is this needed ? */
751 if (dc->pc >= 0x1000 && dc->pc < 0x2000) {
752 env->regs[R_PC] = dc->pc;
753 t_gen_helper_raise_exception(dc, 0xaa);
754 return;
756 #endif
757 code = cpu_ldl_code(env, dc->pc);
758 op = get_opcode(code);
760 if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
761 goto illegal_op;
764 dc->zero = NULL;
766 instr = &i_type_instructions[op];
767 instr->handler(dc, code, instr->flags);
769 if (dc->zero) {
770 tcg_temp_free(dc->zero);
773 return;
775 illegal_op:
776 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
779 static const char * const regnames[] = {
780 "zero", "at", "r2", "r3",
781 "r4", "r5", "r6", "r7",
782 "r8", "r9", "r10", "r11",
783 "r12", "r13", "r14", "r15",
784 "r16", "r17", "r18", "r19",
785 "r20", "r21", "r22", "r23",
786 "et", "bt", "gp", "sp",
787 "fp", "ea", "ba", "ra",
788 "status", "estatus", "bstatus", "ienable",
789 "ipending", "cpuid", "reserved0", "exception",
790 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
791 "badaddr", "config", "mpubase", "mpuacc",
792 "reserved2", "reserved3", "reserved4", "reserved5",
793 "reserved6", "reserved7", "reserved8", "reserved9",
794 "reserved10", "reserved11", "reserved12", "reserved13",
795 "reserved14", "reserved15", "reserved16", "reserved17",
796 "rpc"
799 static TCGv cpu_R[NUM_CORE_REGS];
801 #include "exec/gen-icount.h"
803 static void gen_exception(DisasContext *dc, uint32_t excp)
805 TCGv_i32 tmp = tcg_const_i32(excp);
807 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
808 gen_helper_raise_exception(cpu_env, tmp);
809 tcg_temp_free_i32(tmp);
810 dc->is_jmp = DISAS_NORETURN;
813 /* generate intermediate code for basic block 'tb'. */
814 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
816 CPUNios2State *env = cs->env_ptr;
817 DisasContext dc1, *dc = &dc1;
818 int num_insns;
820 /* Initialize DC */
821 dc->cpu_env = cpu_env;
822 dc->cpu_R = cpu_R;
823 dc->is_jmp = DISAS_NEXT;
824 dc->pc = tb->pc;
825 dc->tb = tb;
826 dc->mem_idx = cpu_mmu_index(env, false);
827 dc->singlestep_enabled = cs->singlestep_enabled;
829 /* Set up instruction counts */
830 num_insns = 0;
831 if (max_insns > 1) {
832 int page_insns = (TARGET_PAGE_SIZE - (tb->pc & TARGET_PAGE_MASK)) / 4;
833 if (max_insns > page_insns) {
834 max_insns = page_insns;
838 gen_tb_start(tb);
839 do {
840 tcg_gen_insn_start(dc->pc);
841 num_insns++;
843 if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
844 gen_exception(dc, EXCP_DEBUG);
845 /* The address covered by the breakpoint must be included in
846 [tb->pc, tb->pc + tb->size) in order to for it to be
847 properly cleared -- thus we increment the PC here so that
848 the logic setting tb->size below does the right thing. */
849 dc->pc += 4;
850 break;
853 if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
854 gen_io_start();
857 /* Decode an instruction */
858 handle_instruction(dc, env);
860 dc->pc += 4;
862 /* Translation stops when a conditional branch is encountered.
863 * Otherwise the subsequent code could get translated several times.
864 * Also stop translation when a page boundary is reached. This
865 * ensures prefetch aborts occur at the right place. */
866 } while (!dc->is_jmp &&
867 !tcg_op_buf_full() &&
868 num_insns < max_insns);
870 /* Indicate where the next block should start */
871 switch (dc->is_jmp) {
872 case DISAS_NEXT:
873 case DISAS_UPDATE:
874 /* Save the current PC back into the CPU register */
875 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
876 tcg_gen_exit_tb(NULL, 0);
877 break;
879 default:
880 case DISAS_JUMP:
881 /* The jump will already have updated the PC register */
882 tcg_gen_exit_tb(NULL, 0);
883 break;
885 case DISAS_NORETURN:
886 case DISAS_TB_JUMP:
887 /* nothing more to generate */
888 break;
891 /* End off the block */
892 gen_tb_end(tb, num_insns);
894 /* Mark instruction starts for the final generated instruction */
895 tb->size = dc->pc - tb->pc;
896 tb->icount = num_insns;
898 #ifdef DEBUG_DISAS
899 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
900 && qemu_log_in_addr_range(tb->pc)) {
901 FILE *logfile = qemu_log_lock();
902 qemu_log("IN: %s\n", lookup_symbol(tb->pc));
903 log_target_disas(cs, tb->pc, dc->pc - tb->pc);
904 qemu_log("\n");
905 qemu_log_unlock(logfile);
907 #endif
910 void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
912 Nios2CPU *cpu = NIOS2_CPU(cs);
913 CPUNios2State *env = &cpu->env;
914 int i;
916 if (!env) {
917 return;
920 qemu_fprintf(f, "IN: PC=%x %s\n",
921 env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
923 for (i = 0; i < NUM_CORE_REGS; i++) {
924 qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
925 if ((i + 1) % 4 == 0) {
926 qemu_fprintf(f, "\n");
929 #if !defined(CONFIG_USER_ONLY)
930 qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
931 env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
932 (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
933 env->mmu.tlbacc_wr);
934 #endif
935 qemu_fprintf(f, "\n\n");
938 void nios2_tcg_init(void)
940 int i;
942 for (i = 0; i < NUM_CORE_REGS; i++) {
943 cpu_R[i] = tcg_global_mem_new(cpu_env,
944 offsetof(CPUNios2State, regs[i]),
945 regnames[i]);
949 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
950 target_ulong *data)
952 env->regs[R_PC] = data[0];