qemu_log_lock/unlock now preserves the qemu_logfile handle.
[qemu/ar7.git] / target / nios2 / translate.c
blob82107bf270f1c345e6364ed879e5f886a20c0a29
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-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"
36 /* is_jmp field values */
37 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
38 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
39 #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
41 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
42 #define INSTRUCTION(func) \
43 INSTRUCTION_FLG(func, 0)
44 #define INSTRUCTION_NOP() \
45 INSTRUCTION_FLG(nop, 0)
46 #define INSTRUCTION_UNIMPLEMENTED() \
47 INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
48 #define INSTRUCTION_ILLEGAL() \
49 INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
51 /* Special R-Type instruction opcode */
52 #define INSN_R_TYPE 0x3A
54 /* I-Type instruction parsing */
55 #define I_TYPE(instr, code) \
56 struct { \
57 uint8_t op; \
58 union { \
59 uint16_t u; \
60 int16_t s; \
61 } imm16; \
62 uint8_t b; \
63 uint8_t a; \
64 } (instr) = { \
65 .op = extract32((code), 0, 6), \
66 .imm16.u = extract32((code), 6, 16), \
67 .b = extract32((code), 22, 5), \
68 .a = extract32((code), 27, 5), \
71 /* R-Type instruction parsing */
72 #define R_TYPE(instr, code) \
73 struct { \
74 uint8_t op; \
75 uint8_t imm5; \
76 uint8_t opx; \
77 uint8_t c; \
78 uint8_t b; \
79 uint8_t a; \
80 } (instr) = { \
81 .op = extract32((code), 0, 6), \
82 .imm5 = extract32((code), 6, 5), \
83 .opx = extract32((code), 11, 6), \
84 .c = extract32((code), 17, 5), \
85 .b = extract32((code), 22, 5), \
86 .a = extract32((code), 27, 5), \
89 /* J-Type instruction parsing */
90 #define J_TYPE(instr, code) \
91 struct { \
92 uint8_t op; \
93 uint32_t imm26; \
94 } (instr) = { \
95 .op = extract32((code), 0, 6), \
96 .imm26 = extract32((code), 6, 26), \
99 typedef struct DisasContext {
100 TCGv_ptr cpu_env;
101 TCGv *cpu_R;
102 TCGv_i32 zero;
103 int is_jmp;
104 target_ulong pc;
105 TranslationBlock *tb;
106 int mem_idx;
107 bool singlestep_enabled;
108 } DisasContext;
110 typedef struct Nios2Instruction {
111 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
112 uint32_t flags;
113 } Nios2Instruction;
115 static uint8_t get_opcode(uint32_t code)
117 I_TYPE(instr, code);
118 return instr.op;
121 static uint8_t get_opxcode(uint32_t code)
123 R_TYPE(instr, code);
124 return instr.opx;
127 static TCGv load_zero(DisasContext *dc)
129 if (!dc->zero) {
130 dc->zero = tcg_const_i32(0);
132 return dc->zero;
135 static TCGv load_gpr(DisasContext *dc, uint8_t reg)
137 if (likely(reg != R_ZERO)) {
138 return dc->cpu_R[reg];
139 } else {
140 return load_zero(dc);
144 static void t_gen_helper_raise_exception(DisasContext *dc,
145 uint32_t index)
147 TCGv_i32 tmp = tcg_const_i32(index);
149 tcg_gen_movi_tl(dc->cpu_R[R_PC], dc->pc);
150 gen_helper_raise_exception(dc->cpu_env, tmp);
151 tcg_temp_free_i32(tmp);
152 dc->is_jmp = DISAS_UPDATE;
155 static bool use_goto_tb(DisasContext *dc, uint32_t dest)
157 if (unlikely(dc->singlestep_enabled)) {
158 return false;
161 #ifndef CONFIG_USER_ONLY
162 return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
163 #else
164 return true;
165 #endif
168 static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
170 TranslationBlock *tb = dc->tb;
172 if (use_goto_tb(dc, dest)) {
173 tcg_gen_goto_tb(n);
174 tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
175 tcg_gen_exit_tb(tb, n);
176 } else {
177 tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
178 tcg_gen_exit_tb(NULL, 0);
182 static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
184 t_gen_helper_raise_exception(dc, flags);
187 static void gen_check_supervisor(DisasContext *dc)
189 if (dc->tb->flags & CR_STATUS_U) {
190 /* CPU in user mode, privileged instruction called, stop. */
191 t_gen_helper_raise_exception(dc, EXCP_SUPERI);
196 * Used as a placeholder for all instructions which do not have
197 * an effect on the simulator (e.g. flush, sync)
199 static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
201 /* Nothing to do here */
205 * J-Type instructions
207 static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
209 J_TYPE(instr, code);
210 gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
211 dc->is_jmp = DISAS_TB_JUMP;
214 static void call(DisasContext *dc, uint32_t code, uint32_t flags)
216 tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
217 jmpi(dc, code, flags);
221 * I-Type instructions
223 /* Load instructions */
224 static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
226 I_TYPE(instr, code);
228 TCGv addr = tcg_temp_new();
229 TCGv data;
232 * WARNING: Loads into R_ZERO are ignored, but we must generate the
233 * memory access itself to emulate the CPU precisely. Load
234 * from a protected page to R_ZERO will cause SIGSEGV on
235 * the Nios2 CPU.
237 if (likely(instr.b != R_ZERO)) {
238 data = dc->cpu_R[instr.b];
239 } else {
240 data = tcg_temp_new();
243 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
244 tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
246 if (unlikely(instr.b == R_ZERO)) {
247 tcg_temp_free(data);
250 tcg_temp_free(addr);
253 /* Store instructions */
254 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
256 I_TYPE(instr, code);
257 TCGv val = load_gpr(dc, instr.b);
259 TCGv addr = tcg_temp_new();
260 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
261 tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
262 tcg_temp_free(addr);
265 /* Branch instructions */
266 static void br(DisasContext *dc, uint32_t code, uint32_t flags)
268 I_TYPE(instr, code);
270 gen_goto_tb(dc, 0, dc->pc + 4 + (instr.imm16.s & -4));
271 dc->is_jmp = DISAS_TB_JUMP;
274 static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
276 I_TYPE(instr, code);
278 TCGLabel *l1 = gen_new_label();
279 tcg_gen_brcond_tl(flags, dc->cpu_R[instr.a], dc->cpu_R[instr.b], l1);
280 gen_goto_tb(dc, 0, dc->pc + 4);
281 gen_set_label(l1);
282 gen_goto_tb(dc, 1, dc->pc + 4 + (instr.imm16.s & -4));
283 dc->is_jmp = DISAS_TB_JUMP;
286 /* Comparison instructions */
287 #define gen_i_cmpxx(fname, op3) \
288 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
290 I_TYPE(instr, (code)); \
291 tcg_gen_setcondi_tl(flags, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
292 (op3)); \
295 gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s)
296 gen_i_cmpxx(gen_cmpxxui, instr.imm16.u)
298 /* Math/logic instructions */
299 #define gen_i_math_logic(fname, insn, resimm, op3) \
300 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
302 I_TYPE(instr, (code)); \
303 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
304 return; \
305 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
306 tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0); \
307 } else { \
308 tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
309 (op3)); \
313 gen_i_math_logic(addi, addi, 1, instr.imm16.s)
314 gen_i_math_logic(muli, muli, 0, instr.imm16.s)
316 gen_i_math_logic(andi, andi, 0, instr.imm16.u)
317 gen_i_math_logic(ori, ori, 1, instr.imm16.u)
318 gen_i_math_logic(xori, xori, 1, instr.imm16.u)
320 gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16)
321 gen_i_math_logic(orhi , ori, 1, instr.imm16.u << 16)
322 gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16)
324 /* Prototype only, defined below */
325 static void handle_r_type_instr(DisasContext *dc, uint32_t code,
326 uint32_t flags);
328 static const Nios2Instruction i_type_instructions[] = {
329 INSTRUCTION(call), /* call */
330 INSTRUCTION(jmpi), /* jmpi */
331 INSTRUCTION_ILLEGAL(),
332 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */
333 INSTRUCTION(addi), /* addi */
334 INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */
335 INSTRUCTION(br), /* br */
336 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */
337 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */
338 INSTRUCTION_ILLEGAL(),
339 INSTRUCTION_ILLEGAL(),
340 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhu */
341 INSTRUCTION(andi), /* andi */
342 INSTRUCTION_FLG(gen_stx, MO_UW), /* sth */
343 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */
344 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldh */
345 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */
346 INSTRUCTION_ILLEGAL(),
347 INSTRUCTION_ILLEGAL(),
348 INSTRUCTION_NOP(), /* initda */
349 INSTRUCTION(ori), /* ori */
350 INSTRUCTION_FLG(gen_stx, MO_UL), /* stw */
351 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */
352 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldw */
353 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */
354 INSTRUCTION_ILLEGAL(),
355 INSTRUCTION_ILLEGAL(),
356 INSTRUCTION_NOP(), /* flushda */
357 INSTRUCTION(xori), /* xori */
358 INSTRUCTION_ILLEGAL(),
359 INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */
360 INSTRUCTION_ILLEGAL(),
361 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */
362 INSTRUCTION_ILLEGAL(),
363 INSTRUCTION_ILLEGAL(),
364 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */
365 INSTRUCTION(muli), /* muli */
366 INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */
367 INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */
368 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */
369 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */
370 INSTRUCTION_ILLEGAL(),
371 INSTRUCTION_ILLEGAL(),
372 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhuio */
373 INSTRUCTION(andhi), /* andhi */
374 INSTRUCTION_FLG(gen_stx, MO_UW), /* sthio */
375 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */
376 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldhio */
377 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */
378 INSTRUCTION_ILLEGAL(),
379 INSTRUCTION_UNIMPLEMENTED(), /* custom */
380 INSTRUCTION_NOP(), /* initd */
381 INSTRUCTION(orhi), /* orhi */
382 INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */
383 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */
384 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */
385 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
386 INSTRUCTION_ILLEGAL(),
387 INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */
388 INSTRUCTION_NOP(), /* flushd */
389 INSTRUCTION(xorhi), /* xorhi */
390 INSTRUCTION_ILLEGAL(),
391 INSTRUCTION_ILLEGAL(),
392 INSTRUCTION_ILLEGAL(),
396 * R-Type instructions
399 * status <- estatus
400 * PC <- ea
402 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
404 tcg_gen_mov_tl(dc->cpu_R[CR_STATUS], dc->cpu_R[CR_ESTATUS]);
405 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_EA]);
407 dc->is_jmp = DISAS_JUMP;
410 /* PC <- ra */
411 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
413 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_RA]);
415 dc->is_jmp = DISAS_JUMP;
418 /* PC <- ba */
419 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
421 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_BA]);
423 dc->is_jmp = DISAS_JUMP;
426 /* PC <- rA */
427 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
429 R_TYPE(instr, code);
431 tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
433 dc->is_jmp = DISAS_JUMP;
436 /* rC <- PC + 4 */
437 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
439 R_TYPE(instr, code);
441 if (likely(instr.c != R_ZERO)) {
442 tcg_gen_movi_tl(dc->cpu_R[instr.c], dc->pc + 4);
447 * ra <- PC + 4
448 * PC <- rA
450 static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
452 R_TYPE(instr, code);
454 tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
455 tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
457 dc->is_jmp = DISAS_JUMP;
460 /* rC <- ctlN */
461 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
463 R_TYPE(instr, code);
465 gen_check_supervisor(dc);
467 switch (instr.imm5 + CR_BASE) {
468 case CR_PTEADDR:
469 case CR_TLBACC:
470 case CR_TLBMISC:
472 #if !defined(CONFIG_USER_ONLY)
473 if (likely(instr.c != R_ZERO)) {
474 tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
475 #ifdef DEBUG_MMU
476 TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
477 gen_helper_mmu_read_debug(dc->cpu_R[instr.c], dc->cpu_env, tmp);
478 tcg_temp_free_i32(tmp);
479 #endif
481 #endif
482 break;
485 default:
486 if (likely(instr.c != R_ZERO)) {
487 tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
489 break;
493 /* ctlN <- rA */
494 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
496 R_TYPE(instr, code);
498 gen_check_supervisor(dc);
500 switch (instr.imm5 + CR_BASE) {
501 case CR_PTEADDR:
502 case CR_TLBACC:
503 case CR_TLBMISC:
505 #if !defined(CONFIG_USER_ONLY)
506 TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
507 gen_helper_mmu_write(dc->cpu_env, tmp, load_gpr(dc, instr.a));
508 tcg_temp_free_i32(tmp);
509 #endif
510 break;
513 default:
514 tcg_gen_mov_tl(dc->cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a));
515 break;
518 /* If interrupts were enabled using WRCTL, trigger them. */
519 #if !defined(CONFIG_USER_ONLY)
520 if ((instr.imm5 + CR_BASE) == CR_STATUS) {
521 gen_helper_check_interrupts(dc->cpu_env);
523 #endif
526 /* Comparison instructions */
527 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
529 R_TYPE(instr, code);
530 if (likely(instr.c != R_ZERO)) {
531 tcg_gen_setcond_tl(flags, dc->cpu_R[instr.c], dc->cpu_R[instr.a],
532 dc->cpu_R[instr.b]);
536 /* Math/logic instructions */
537 #define gen_r_math_logic(fname, insn, op3) \
538 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
540 R_TYPE(instr, (code)); \
541 if (likely(instr.c != R_ZERO)) { \
542 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), \
543 (op3)); \
547 gen_r_math_logic(add, add_tl, load_gpr(dc, instr.b))
548 gen_r_math_logic(sub, sub_tl, load_gpr(dc, instr.b))
549 gen_r_math_logic(mul, mul_tl, load_gpr(dc, instr.b))
551 gen_r_math_logic(and, and_tl, load_gpr(dc, instr.b))
552 gen_r_math_logic(or, or_tl, load_gpr(dc, instr.b))
553 gen_r_math_logic(xor, xor_tl, load_gpr(dc, instr.b))
554 gen_r_math_logic(nor, nor_tl, load_gpr(dc, instr.b))
556 gen_r_math_logic(srai, sari_tl, instr.imm5)
557 gen_r_math_logic(srli, shri_tl, instr.imm5)
558 gen_r_math_logic(slli, shli_tl, instr.imm5)
559 gen_r_math_logic(roli, rotli_tl, instr.imm5)
561 #define gen_r_mul(fname, insn) \
562 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
564 R_TYPE(instr, (code)); \
565 if (likely(instr.c != R_ZERO)) { \
566 TCGv t0 = tcg_temp_new(); \
567 tcg_gen_##insn(t0, dc->cpu_R[instr.c], \
568 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
569 tcg_temp_free(t0); \
573 gen_r_mul(mulxss, muls2_tl)
574 gen_r_mul(mulxuu, mulu2_tl)
575 gen_r_mul(mulxsu, mulsu2_tl)
577 #define gen_r_shift_s(fname, insn) \
578 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
580 R_TYPE(instr, (code)); \
581 if (likely(instr.c != R_ZERO)) { \
582 TCGv t0 = tcg_temp_new(); \
583 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
584 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
585 tcg_temp_free(t0); \
589 gen_r_shift_s(sra, sar_tl)
590 gen_r_shift_s(srl, shr_tl)
591 gen_r_shift_s(sll, shl_tl)
592 gen_r_shift_s(rol, rotl_tl)
593 gen_r_shift_s(ror, rotr_tl)
595 static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
597 R_TYPE(instr, (code));
599 /* Stores into R_ZERO are ignored */
600 if (unlikely(instr.c == R_ZERO)) {
601 return;
604 TCGv t0 = tcg_temp_new();
605 TCGv t1 = tcg_temp_new();
606 TCGv t2 = tcg_temp_new();
607 TCGv t3 = tcg_temp_new();
609 tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a));
610 tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b));
611 tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
612 tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
613 tcg_gen_and_tl(t2, t2, t3);
614 tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
615 tcg_gen_or_tl(t2, t2, t3);
616 tcg_gen_movi_tl(t3, 0);
617 tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
618 tcg_gen_div_tl(dc->cpu_R[instr.c], t0, t1);
619 tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
621 tcg_temp_free(t3);
622 tcg_temp_free(t2);
623 tcg_temp_free(t1);
624 tcg_temp_free(t0);
627 static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
629 R_TYPE(instr, (code));
631 /* Stores into R_ZERO are ignored */
632 if (unlikely(instr.c == R_ZERO)) {
633 return;
636 TCGv t0 = tcg_temp_new();
637 TCGv t1 = tcg_temp_new();
638 TCGv t2 = tcg_const_tl(0);
639 TCGv t3 = tcg_const_tl(1);
641 tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
642 tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
643 tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
644 tcg_gen_divu_tl(dc->cpu_R[instr.c], t0, t1);
645 tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
647 tcg_temp_free(t3);
648 tcg_temp_free(t2);
649 tcg_temp_free(t1);
650 tcg_temp_free(t0);
653 static const Nios2Instruction r_type_instructions[] = {
654 INSTRUCTION_ILLEGAL(),
655 INSTRUCTION(eret), /* eret */
656 INSTRUCTION(roli), /* roli */
657 INSTRUCTION(rol), /* rol */
658 INSTRUCTION_NOP(), /* flushp */
659 INSTRUCTION(ret), /* ret */
660 INSTRUCTION(nor), /* nor */
661 INSTRUCTION(mulxuu), /* mulxuu */
662 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */
663 INSTRUCTION(bret), /* bret */
664 INSTRUCTION_ILLEGAL(),
665 INSTRUCTION(ror), /* ror */
666 INSTRUCTION_NOP(), /* flushi */
667 INSTRUCTION(jmp), /* jmp */
668 INSTRUCTION(and), /* and */
669 INSTRUCTION_ILLEGAL(),
670 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */
671 INSTRUCTION_ILLEGAL(),
672 INSTRUCTION(slli), /* slli */
673 INSTRUCTION(sll), /* sll */
674 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
675 INSTRUCTION_ILLEGAL(),
676 INSTRUCTION(or), /* or */
677 INSTRUCTION(mulxsu), /* mulxsu */
678 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */
679 INSTRUCTION_ILLEGAL(),
680 INSTRUCTION(srli), /* srli */
681 INSTRUCTION(srl), /* srl */
682 INSTRUCTION(nextpc), /* nextpc */
683 INSTRUCTION(callr), /* callr */
684 INSTRUCTION(xor), /* xor */
685 INSTRUCTION(mulxss), /* mulxss */
686 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */
687 INSTRUCTION_ILLEGAL(),
688 INSTRUCTION_ILLEGAL(),
689 INSTRUCTION_ILLEGAL(),
690 INSTRUCTION(divu), /* divu */
691 INSTRUCTION(divs), /* div */
692 INSTRUCTION(rdctl), /* rdctl */
693 INSTRUCTION(mul), /* mul */
694 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */
695 INSTRUCTION_NOP(), /* initi */
696 INSTRUCTION_ILLEGAL(),
697 INSTRUCTION_ILLEGAL(),
698 INSTRUCTION_ILLEGAL(),
699 INSTRUCTION_FLG(gen_excp, EXCP_TRAP), /* trap */
700 INSTRUCTION(wrctl), /* wrctl */
701 INSTRUCTION_ILLEGAL(),
702 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */
703 INSTRUCTION(add), /* add */
704 INSTRUCTION_ILLEGAL(),
705 INSTRUCTION_ILLEGAL(),
706 INSTRUCTION_FLG(gen_excp, EXCP_BREAK), /* break */
707 INSTRUCTION_ILLEGAL(),
708 INSTRUCTION(nop), /* nop */
709 INSTRUCTION_ILLEGAL(),
710 INSTRUCTION_ILLEGAL(),
711 INSTRUCTION(sub), /* sub */
712 INSTRUCTION(srai), /* srai */
713 INSTRUCTION(sra), /* sra */
714 INSTRUCTION_ILLEGAL(),
715 INSTRUCTION_ILLEGAL(),
716 INSTRUCTION_ILLEGAL(),
717 INSTRUCTION_ILLEGAL(),
720 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
722 uint8_t opx;
723 const Nios2Instruction *instr;
725 opx = get_opxcode(code);
726 if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
727 goto illegal_op;
730 instr = &r_type_instructions[opx];
731 instr->handler(dc, code, instr->flags);
733 return;
735 illegal_op:
736 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
739 static void handle_instruction(DisasContext *dc, CPUNios2State *env)
741 uint32_t code;
742 uint8_t op;
743 const Nios2Instruction *instr;
744 #if defined(CONFIG_USER_ONLY)
745 /* FIXME: Is this needed ? */
746 if (dc->pc >= 0x1000 && dc->pc < 0x2000) {
747 env->regs[R_PC] = dc->pc;
748 t_gen_helper_raise_exception(dc, 0xaa);
749 return;
751 #endif
752 code = cpu_ldl_code(env, dc->pc);
753 op = get_opcode(code);
755 if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
756 goto illegal_op;
759 dc->zero = NULL;
761 instr = &i_type_instructions[op];
762 instr->handler(dc, code, instr->flags);
764 if (dc->zero) {
765 tcg_temp_free(dc->zero);
768 return;
770 illegal_op:
771 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
774 static const char * const regnames[] = {
775 "zero", "at", "r2", "r3",
776 "r4", "r5", "r6", "r7",
777 "r8", "r9", "r10", "r11",
778 "r12", "r13", "r14", "r15",
779 "r16", "r17", "r18", "r19",
780 "r20", "r21", "r22", "r23",
781 "et", "bt", "gp", "sp",
782 "fp", "ea", "ba", "ra",
783 "status", "estatus", "bstatus", "ienable",
784 "ipending", "cpuid", "reserved0", "exception",
785 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
786 "badaddr", "config", "mpubase", "mpuacc",
787 "reserved2", "reserved3", "reserved4", "reserved5",
788 "reserved6", "reserved7", "reserved8", "reserved9",
789 "reserved10", "reserved11", "reserved12", "reserved13",
790 "reserved14", "reserved15", "reserved16", "reserved17",
791 "rpc"
794 static TCGv cpu_R[NUM_CORE_REGS];
796 #include "exec/gen-icount.h"
798 static void gen_exception(DisasContext *dc, uint32_t excp)
800 TCGv_i32 tmp = tcg_const_i32(excp);
802 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
803 gen_helper_raise_exception(cpu_env, tmp);
804 tcg_temp_free_i32(tmp);
805 dc->is_jmp = DISAS_UPDATE;
808 /* generate intermediate code for basic block 'tb'. */
809 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
811 CPUNios2State *env = cs->env_ptr;
812 DisasContext dc1, *dc = &dc1;
813 int num_insns;
815 /* Initialize DC */
816 dc->cpu_env = cpu_env;
817 dc->cpu_R = cpu_R;
818 dc->is_jmp = DISAS_NEXT;
819 dc->pc = tb->pc;
820 dc->tb = tb;
821 dc->mem_idx = cpu_mmu_index(env, false);
822 dc->singlestep_enabled = cs->singlestep_enabled;
824 /* Set up instruction counts */
825 num_insns = 0;
826 if (max_insns > 1) {
827 int page_insns = (TARGET_PAGE_SIZE - (tb->pc & TARGET_PAGE_MASK)) / 4;
828 if (max_insns > page_insns) {
829 max_insns = page_insns;
833 gen_tb_start(tb);
834 do {
835 tcg_gen_insn_start(dc->pc);
836 num_insns++;
838 if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
839 gen_exception(dc, EXCP_DEBUG);
840 /* The address covered by the breakpoint must be included in
841 [tb->pc, tb->pc + tb->size) in order to for it to be
842 properly cleared -- thus we increment the PC here so that
843 the logic setting tb->size below does the right thing. */
844 dc->pc += 4;
845 break;
848 if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
849 gen_io_start();
852 /* Decode an instruction */
853 handle_instruction(dc, env);
855 dc->pc += 4;
857 /* Translation stops when a conditional branch is encountered.
858 * Otherwise the subsequent code could get translated several times.
859 * Also stop translation when a page boundary is reached. This
860 * ensures prefetch aborts occur at the right place. */
861 } while (!dc->is_jmp &&
862 !tcg_op_buf_full() &&
863 num_insns < max_insns);
865 /* Indicate where the next block should start */
866 switch (dc->is_jmp) {
867 case DISAS_NEXT:
868 /* Save the current PC back into the CPU register */
869 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
870 tcg_gen_exit_tb(NULL, 0);
871 break;
873 default:
874 case DISAS_JUMP:
875 case DISAS_UPDATE:
876 /* The jump will already have updated the PC register */
877 tcg_gen_exit_tb(NULL, 0);
878 break;
880 case DISAS_TB_JUMP:
881 /* nothing more to generate */
882 break;
885 /* End off the block */
886 gen_tb_end(tb, num_insns);
888 /* Mark instruction starts for the final generated instruction */
889 tb->size = dc->pc - tb->pc;
890 tb->icount = num_insns;
892 #ifdef DEBUG_DISAS
893 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
894 && qemu_log_in_addr_range(tb->pc)) {
895 FILE *logfile = qemu_log_lock();
896 qemu_log("IN: %s\n", lookup_symbol(tb->pc));
897 log_target_disas(cs, tb->pc, dc->pc - tb->pc);
898 qemu_log("\n");
899 qemu_log_unlock(logfile);
901 #endif
904 void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
906 Nios2CPU *cpu = NIOS2_CPU(cs);
907 CPUNios2State *env = &cpu->env;
908 int i;
910 if (!env) {
911 return;
914 qemu_fprintf(f, "IN: PC=%x %s\n",
915 env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
917 for (i = 0; i < NUM_CORE_REGS; i++) {
918 qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
919 if ((i + 1) % 4 == 0) {
920 qemu_fprintf(f, "\n");
923 #if !defined(CONFIG_USER_ONLY)
924 qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
925 env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
926 (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
927 env->mmu.tlbacc_wr);
928 #endif
929 qemu_fprintf(f, "\n\n");
932 void nios2_tcg_init(void)
934 int i;
936 for (i = 0; i < NUM_CORE_REGS; i++) {
937 cpu_R[i] = tcg_global_mem_new(cpu_env,
938 offsetof(CPUNios2State, regs[i]),
939 regnames[i]);
943 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
944 target_ulong *data)
946 env->regs[R_PC] = data[0];