xref: /openbmc/qemu/target/nios2/translate.c (revision 812b31d3)
1 /*
2  * Altera Nios II emulation for qemu: main translation routines.
3  *
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.)
8  *
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.
13  *
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.
18  *
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>
22  */
23 
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"
36 
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 
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)
50 
51 /* Special R-Type instruction opcode */
52 #define INSN_R_TYPE 0x3A
53 
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), \
69     }
70 
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), \
87     }
88 
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), \
97     }
98 
99 typedef struct DisasContext {
100     DisasContextBase  base;
101     TCGv_i32          zero;
102     target_ulong      pc;
103     int               mem_idx;
104 } DisasContext;
105 
106 static TCGv cpu_R[NUM_CORE_REGS];
107 
108 typedef struct Nios2Instruction {
109     void     (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
110     uint32_t  flags;
111 } Nios2Instruction;
112 
113 static uint8_t get_opcode(uint32_t code)
114 {
115     I_TYPE(instr, code);
116     return instr.op;
117 }
118 
119 static uint8_t get_opxcode(uint32_t code)
120 {
121     R_TYPE(instr, code);
122     return instr.opx;
123 }
124 
125 static TCGv load_zero(DisasContext *dc)
126 {
127     if (!dc->zero) {
128         dc->zero = tcg_const_i32(0);
129     }
130     return dc->zero;
131 }
132 
133 static TCGv load_gpr(DisasContext *dc, uint8_t reg)
134 {
135     if (likely(reg != R_ZERO)) {
136         return cpu_R[reg];
137     } else {
138         return load_zero(dc);
139     }
140 }
141 
142 static void t_gen_helper_raise_exception(DisasContext *dc,
143                                          uint32_t index)
144 {
145     TCGv_i32 tmp = tcg_const_i32(index);
146 
147     tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
148     gen_helper_raise_exception(cpu_env, tmp);
149     tcg_temp_free_i32(tmp);
150     dc->base.is_jmp = DISAS_NORETURN;
151 }
152 
153 static bool use_goto_tb(DisasContext *dc, uint32_t dest)
154 {
155     if (unlikely(dc->base.singlestep_enabled)) {
156         return false;
157     }
158 
159 #ifndef CONFIG_USER_ONLY
160     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
161 #else
162     return true;
163 #endif
164 }
165 
166 static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
167 {
168     const TranslationBlock *tb = dc->base.tb;
169 
170     if (use_goto_tb(dc, dest)) {
171         tcg_gen_goto_tb(n);
172         tcg_gen_movi_tl(cpu_R[R_PC], dest);
173         tcg_gen_exit_tb(tb, n);
174     } else {
175         tcg_gen_movi_tl(cpu_R[R_PC], dest);
176         tcg_gen_exit_tb(NULL, 0);
177     }
178 }
179 
180 static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
181 {
182     t_gen_helper_raise_exception(dc, flags);
183 }
184 
185 static void gen_check_supervisor(DisasContext *dc)
186 {
187     if (dc->base.tb->flags & CR_STATUS_U) {
188         /* CPU in user mode, privileged instruction called, stop. */
189         t_gen_helper_raise_exception(dc, EXCP_SUPERI);
190     }
191 }
192 
193 /*
194  * Used as a placeholder for all instructions which do not have
195  * an effect on the simulator (e.g. flush, sync)
196  */
197 static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
198 {
199     /* Nothing to do here */
200 }
201 
202 /*
203  * J-Type instructions
204  */
205 static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
206 {
207     J_TYPE(instr, code);
208     gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
209     dc->base.is_jmp = DISAS_NORETURN;
210 }
211 
212 static void call(DisasContext *dc, uint32_t code, uint32_t flags)
213 {
214     tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next);
215     jmpi(dc, code, flags);
216 }
217 
218 /*
219  * I-Type instructions
220  */
221 /* Load instructions */
222 static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
223 {
224     I_TYPE(instr, code);
225 
226     TCGv addr = tcg_temp_new();
227     TCGv data;
228 
229     /*
230      * WARNING: Loads into R_ZERO are ignored, but we must generate the
231      *          memory access itself to emulate the CPU precisely. Load
232      *          from a protected page to R_ZERO will cause SIGSEGV on
233      *          the Nios2 CPU.
234      */
235     if (likely(instr.b != R_ZERO)) {
236         data = cpu_R[instr.b];
237     } else {
238         data = tcg_temp_new();
239     }
240 
241     tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
242     tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
243 
244     if (unlikely(instr.b == R_ZERO)) {
245         tcg_temp_free(data);
246     }
247 
248     tcg_temp_free(addr);
249 }
250 
251 /* Store instructions */
252 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
253 {
254     I_TYPE(instr, code);
255     TCGv val = load_gpr(dc, instr.b);
256 
257     TCGv addr = tcg_temp_new();
258     tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
259     tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
260     tcg_temp_free(addr);
261 }
262 
263 /* Branch instructions */
264 static void br(DisasContext *dc, uint32_t code, uint32_t flags)
265 {
266     I_TYPE(instr, code);
267 
268     gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4));
269     dc->base.is_jmp = DISAS_NORETURN;
270 }
271 
272 static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
273 {
274     I_TYPE(instr, code);
275 
276     TCGLabel *l1 = gen_new_label();
277     tcg_gen_brcond_tl(flags, cpu_R[instr.a], cpu_R[instr.b], l1);
278     gen_goto_tb(dc, 0, dc->base.pc_next);
279     gen_set_label(l1);
280     gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
281     dc->base.is_jmp = DISAS_NORETURN;
282 }
283 
284 /* Comparison instructions */
285 #define gen_i_cmpxx(fname, op3)                                              \
286 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)         \
287 {                                                                            \
288     I_TYPE(instr, (code));                                                   \
289     tcg_gen_setcondi_tl(flags, cpu_R[instr.b], cpu_R[instr.a], (op3));       \
290 }
291 
292 gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s)
293 gen_i_cmpxx(gen_cmpxxui, instr.imm16.u)
294 
295 /* Math/logic instructions */
296 #define gen_i_math_logic(fname, insn, resimm, op3)                          \
297 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)        \
298 {                                                                           \
299     I_TYPE(instr, (code));                                                  \
300     if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */     \
301         return;                                                             \
302     } else if (instr.a == R_ZERO) { /* MOVxI optimizations */               \
303         tcg_gen_movi_tl(cpu_R[instr.b], (resimm) ? (op3) : 0);              \
304     } else {                                                                \
305         tcg_gen_##insn##_tl(cpu_R[instr.b], cpu_R[instr.a], (op3));         \
306     }                                                                       \
307 }
308 
309 gen_i_math_logic(addi,  addi, 1, instr.imm16.s)
310 gen_i_math_logic(muli,  muli, 0, instr.imm16.s)
311 
312 gen_i_math_logic(andi,  andi, 0, instr.imm16.u)
313 gen_i_math_logic(ori,   ori,  1, instr.imm16.u)
314 gen_i_math_logic(xori,  xori, 1, instr.imm16.u)
315 
316 gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16)
317 gen_i_math_logic(orhi , ori,  1, instr.imm16.u << 16)
318 gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16)
319 
320 /* Prototype only, defined below */
321 static void handle_r_type_instr(DisasContext *dc, uint32_t code,
322                                 uint32_t flags);
323 
324 static const Nios2Instruction i_type_instructions[] = {
325     INSTRUCTION(call),                                /* call */
326     INSTRUCTION(jmpi),                                /* jmpi */
327     INSTRUCTION_ILLEGAL(),
328     INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbu */
329     INSTRUCTION(addi),                                /* addi */
330     INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stb */
331     INSTRUCTION(br),                                  /* br */
332     INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldb */
333     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE),        /* cmpgei */
334     INSTRUCTION_ILLEGAL(),
335     INSTRUCTION_ILLEGAL(),
336     INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhu */
337     INSTRUCTION(andi),                                /* andi */
338     INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sth */
339     INSTRUCTION_FLG(gen_bxx, TCG_COND_GE),            /* bge */
340     INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldh */
341     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT),        /* cmplti */
342     INSTRUCTION_ILLEGAL(),
343     INSTRUCTION_ILLEGAL(),
344     INSTRUCTION_NOP(),                                /* initda */
345     INSTRUCTION(ori),                                 /* ori */
346     INSTRUCTION_FLG(gen_stx, MO_UL),                  /* stw */
347     INSTRUCTION_FLG(gen_bxx, TCG_COND_LT),            /* blt */
348     INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldw */
349     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE),        /* cmpnei */
350     INSTRUCTION_ILLEGAL(),
351     INSTRUCTION_ILLEGAL(),
352     INSTRUCTION_NOP(),                                /* flushda */
353     INSTRUCTION(xori),                                /* xori */
354     INSTRUCTION_ILLEGAL(),
355     INSTRUCTION_FLG(gen_bxx, TCG_COND_NE),            /* bne */
356     INSTRUCTION_ILLEGAL(),
357     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ),        /* cmpeqi */
358     INSTRUCTION_ILLEGAL(),
359     INSTRUCTION_ILLEGAL(),
360     INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbuio */
361     INSTRUCTION(muli),                                /* muli */
362     INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stbio */
363     INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ),            /* beq */
364     INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldbio */
365     INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU),       /* cmpgeui */
366     INSTRUCTION_ILLEGAL(),
367     INSTRUCTION_ILLEGAL(),
368     INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhuio */
369     INSTRUCTION(andhi),                               /* andhi */
370     INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sthio */
371     INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU),           /* bgeu */
372     INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldhio */
373     INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU),       /* cmpltui */
374     INSTRUCTION_ILLEGAL(),
375     INSTRUCTION_UNIMPLEMENTED(),                      /* custom */
376     INSTRUCTION_NOP(),                                /* initd */
377     INSTRUCTION(orhi),                                /* orhi */
378     INSTRUCTION_FLG(gen_stx, MO_SL),                  /* stwio */
379     INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU),           /* bltu */
380     INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldwio */
381     INSTRUCTION_UNIMPLEMENTED(),                      /* rdprs */
382     INSTRUCTION_ILLEGAL(),
383     INSTRUCTION_FLG(handle_r_type_instr, 0),          /* R-Type */
384     INSTRUCTION_NOP(),                                /* flushd */
385     INSTRUCTION(xorhi),                               /* xorhi */
386     INSTRUCTION_ILLEGAL(),
387     INSTRUCTION_ILLEGAL(),
388     INSTRUCTION_ILLEGAL(),
389 };
390 
391 /*
392  * R-Type instructions
393  */
394 /*
395  * status <- estatus
396  * PC <- ea
397  */
398 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
399 {
400     tcg_gen_mov_tl(cpu_R[CR_STATUS], cpu_R[CR_ESTATUS]);
401     tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_EA]);
402 
403     dc->base.is_jmp = DISAS_JUMP;
404 }
405 
406 /* PC <- ra */
407 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
408 {
409     tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_RA]);
410 
411     dc->base.is_jmp = DISAS_JUMP;
412 }
413 
414 /* PC <- ba */
415 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
416 {
417     tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_BA]);
418 
419     dc->base.is_jmp = DISAS_JUMP;
420 }
421 
422 /* PC <- rA */
423 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
424 {
425     R_TYPE(instr, code);
426 
427     tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a));
428 
429     dc->base.is_jmp = DISAS_JUMP;
430 }
431 
432 /* rC <- PC + 4 */
433 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
434 {
435     R_TYPE(instr, code);
436 
437     if (likely(instr.c != R_ZERO)) {
438         tcg_gen_movi_tl(cpu_R[instr.c], dc->base.pc_next);
439     }
440 }
441 
442 /*
443  * ra <- PC + 4
444  * PC <- rA
445  */
446 static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
447 {
448     R_TYPE(instr, code);
449 
450     tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a));
451     tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next);
452 
453     dc->base.is_jmp = DISAS_JUMP;
454 }
455 
456 /* rC <- ctlN */
457 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
458 {
459     R_TYPE(instr, code);
460 
461     gen_check_supervisor(dc);
462 
463     switch (instr.imm5 + CR_BASE) {
464     case CR_PTEADDR:
465     case CR_TLBACC:
466     case CR_TLBMISC:
467     {
468 #if !defined(CONFIG_USER_ONLY)
469         if (likely(instr.c != R_ZERO)) {
470             tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]);
471 #ifdef DEBUG_MMU
472             TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
473             gen_helper_mmu_read_debug(cpu_R[instr.c], cpu_env, tmp);
474             tcg_temp_free_i32(tmp);
475 #endif
476         }
477 #endif
478         break;
479     }
480 
481     default:
482         if (likely(instr.c != R_ZERO)) {
483             tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]);
484         }
485         break;
486     }
487 }
488 
489 /* ctlN <- rA */
490 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
491 {
492     R_TYPE(instr, code);
493 
494     gen_check_supervisor(dc);
495 
496     switch (instr.imm5 + CR_BASE) {
497     case CR_PTEADDR:
498     case CR_TLBACC:
499     case CR_TLBMISC:
500     {
501 #if !defined(CONFIG_USER_ONLY)
502         TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
503         gen_helper_mmu_write(cpu_env, tmp, load_gpr(dc, instr.a));
504         tcg_temp_free_i32(tmp);
505 #endif
506         break;
507     }
508 
509     default:
510         tcg_gen_mov_tl(cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a));
511         break;
512     }
513 
514     /* If interrupts were enabled using WRCTL, trigger them. */
515 #if !defined(CONFIG_USER_ONLY)
516     if ((instr.imm5 + CR_BASE) == CR_STATUS) {
517         if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
518             gen_io_start();
519         }
520         gen_helper_check_interrupts(cpu_env);
521         dc->base.is_jmp = DISAS_UPDATE;
522     }
523 #endif
524 }
525 
526 /* Comparison instructions */
527 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
528 {
529     R_TYPE(instr, code);
530     if (likely(instr.c != R_ZERO)) {
531         tcg_gen_setcond_tl(flags, cpu_R[instr.c], cpu_R[instr.a],
532                            cpu_R[instr.b]);
533     }
534 }
535 
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)       \
539 {                                                                          \
540     R_TYPE(instr, (code));                                                 \
541     if (likely(instr.c != R_ZERO)) {                                       \
542         tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), (op3));    \
543     }                                                                      \
544 }
545 
546 gen_r_math_logic(add,  add_tl,   load_gpr(dc, instr.b))
547 gen_r_math_logic(sub,  sub_tl,   load_gpr(dc, instr.b))
548 gen_r_math_logic(mul,  mul_tl,   load_gpr(dc, instr.b))
549 
550 gen_r_math_logic(and,  and_tl,   load_gpr(dc, instr.b))
551 gen_r_math_logic(or,   or_tl,    load_gpr(dc, instr.b))
552 gen_r_math_logic(xor,  xor_tl,   load_gpr(dc, instr.b))
553 gen_r_math_logic(nor,  nor_tl,   load_gpr(dc, instr.b))
554 
555 gen_r_math_logic(srai, sari_tl,  instr.imm5)
556 gen_r_math_logic(srli, shri_tl,  instr.imm5)
557 gen_r_math_logic(slli, shli_tl,  instr.imm5)
558 gen_r_math_logic(roli, rotli_tl, instr.imm5)
559 
560 #define gen_r_mul(fname, insn)                                         \
561 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)   \
562 {                                                                      \
563     R_TYPE(instr, (code));                                             \
564     if (likely(instr.c != R_ZERO)) {                                   \
565         TCGv t0 = tcg_temp_new();                                      \
566         tcg_gen_##insn(t0, cpu_R[instr.c],                             \
567                        load_gpr(dc, instr.a), load_gpr(dc, instr.b));  \
568         tcg_temp_free(t0);                                             \
569     }                                                                  \
570 }
571 
572 gen_r_mul(mulxss, muls2_tl)
573 gen_r_mul(mulxuu, mulu2_tl)
574 gen_r_mul(mulxsu, mulsu2_tl)
575 
576 #define gen_r_shift_s(fname, insn)                                         \
577 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
578 {                                                                          \
579     R_TYPE(instr, (code));                                                 \
580     if (likely(instr.c != R_ZERO)) {                                       \
581         TCGv t0 = tcg_temp_new();                                          \
582         tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31);                  \
583         tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), t0);       \
584         tcg_temp_free(t0);                                                 \
585     }                                                                      \
586 }
587 
588 gen_r_shift_s(sra, sar_tl)
589 gen_r_shift_s(srl, shr_tl)
590 gen_r_shift_s(sll, shl_tl)
591 gen_r_shift_s(rol, rotl_tl)
592 gen_r_shift_s(ror, rotr_tl)
593 
594 static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
595 {
596     R_TYPE(instr, (code));
597 
598     /* Stores into R_ZERO are ignored */
599     if (unlikely(instr.c == R_ZERO)) {
600         return;
601     }
602 
603     TCGv t0 = tcg_temp_new();
604     TCGv t1 = tcg_temp_new();
605     TCGv t2 = tcg_temp_new();
606     TCGv t3 = tcg_temp_new();
607 
608     tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a));
609     tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b));
610     tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
611     tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
612     tcg_gen_and_tl(t2, t2, t3);
613     tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
614     tcg_gen_or_tl(t2, t2, t3);
615     tcg_gen_movi_tl(t3, 0);
616     tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
617     tcg_gen_div_tl(cpu_R[instr.c], t0, t1);
618     tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
619 
620     tcg_temp_free(t3);
621     tcg_temp_free(t2);
622     tcg_temp_free(t1);
623     tcg_temp_free(t0);
624 }
625 
626 static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
627 {
628     R_TYPE(instr, (code));
629 
630     /* Stores into R_ZERO are ignored */
631     if (unlikely(instr.c == R_ZERO)) {
632         return;
633     }
634 
635     TCGv t0 = tcg_temp_new();
636     TCGv t1 = tcg_temp_new();
637     TCGv t2 = tcg_const_tl(0);
638     TCGv t3 = tcg_const_tl(1);
639 
640     tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
641     tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
642     tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
643     tcg_gen_divu_tl(cpu_R[instr.c], t0, t1);
644     tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
645 
646     tcg_temp_free(t3);
647     tcg_temp_free(t2);
648     tcg_temp_free(t1);
649     tcg_temp_free(t0);
650 }
651 
652 static const Nios2Instruction r_type_instructions[] = {
653     INSTRUCTION_ILLEGAL(),
654     INSTRUCTION(eret),                                /* eret */
655     INSTRUCTION(roli),                                /* roli */
656     INSTRUCTION(rol),                                 /* rol */
657     INSTRUCTION_NOP(),                                /* flushp */
658     INSTRUCTION(ret),                                 /* ret */
659     INSTRUCTION(nor),                                 /* nor */
660     INSTRUCTION(mulxuu),                              /* mulxuu */
661     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),          /* cmpge */
662     INSTRUCTION(bret),                                /* bret */
663     INSTRUCTION_ILLEGAL(),
664     INSTRUCTION(ror),                                 /* ror */
665     INSTRUCTION_NOP(),                                /* flushi */
666     INSTRUCTION(jmp),                                 /* jmp */
667     INSTRUCTION(and),                                 /* and */
668     INSTRUCTION_ILLEGAL(),
669     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),          /* cmplt */
670     INSTRUCTION_ILLEGAL(),
671     INSTRUCTION(slli),                                /* slli */
672     INSTRUCTION(sll),                                 /* sll */
673     INSTRUCTION_UNIMPLEMENTED(),                      /* wrprs */
674     INSTRUCTION_ILLEGAL(),
675     INSTRUCTION(or),                                  /* or */
676     INSTRUCTION(mulxsu),                              /* mulxsu */
677     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),          /* cmpne */
678     INSTRUCTION_ILLEGAL(),
679     INSTRUCTION(srli),                                /* srli */
680     INSTRUCTION(srl),                                 /* srl */
681     INSTRUCTION(nextpc),                              /* nextpc */
682     INSTRUCTION(callr),                               /* callr */
683     INSTRUCTION(xor),                                 /* xor */
684     INSTRUCTION(mulxss),                              /* mulxss */
685     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),          /* cmpeq */
686     INSTRUCTION_ILLEGAL(),
687     INSTRUCTION_ILLEGAL(),
688     INSTRUCTION_ILLEGAL(),
689     INSTRUCTION(divu),                                /* divu */
690     INSTRUCTION(divs),                                /* div */
691     INSTRUCTION(rdctl),                               /* rdctl */
692     INSTRUCTION(mul),                                 /* mul */
693     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),         /* cmpgeu */
694     INSTRUCTION_NOP(),                                /* initi */
695     INSTRUCTION_ILLEGAL(),
696     INSTRUCTION_ILLEGAL(),
697     INSTRUCTION_ILLEGAL(),
698     INSTRUCTION_FLG(gen_excp, EXCP_TRAP),             /* trap */
699     INSTRUCTION(wrctl),                               /* wrctl */
700     INSTRUCTION_ILLEGAL(),
701     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),         /* cmpltu */
702     INSTRUCTION(add),                                 /* add */
703     INSTRUCTION_ILLEGAL(),
704     INSTRUCTION_ILLEGAL(),
705     INSTRUCTION_FLG(gen_excp, EXCP_BREAK),            /* break */
706     INSTRUCTION_ILLEGAL(),
707     INSTRUCTION(nop),                                 /* nop */
708     INSTRUCTION_ILLEGAL(),
709     INSTRUCTION_ILLEGAL(),
710     INSTRUCTION(sub),                                 /* sub */
711     INSTRUCTION(srai),                                /* srai */
712     INSTRUCTION(sra),                                 /* sra */
713     INSTRUCTION_ILLEGAL(),
714     INSTRUCTION_ILLEGAL(),
715     INSTRUCTION_ILLEGAL(),
716     INSTRUCTION_ILLEGAL(),
717 };
718 
719 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
720 {
721     uint8_t opx;
722     const Nios2Instruction *instr;
723 
724     opx = get_opxcode(code);
725     if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
726         goto illegal_op;
727     }
728 
729     instr = &r_type_instructions[opx];
730     instr->handler(dc, code, instr->flags);
731 
732     return;
733 
734 illegal_op:
735     t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
736 }
737 
738 static const char * const regnames[] = {
739     "zero",       "at",         "r2",         "r3",
740     "r4",         "r5",         "r6",         "r7",
741     "r8",         "r9",         "r10",        "r11",
742     "r12",        "r13",        "r14",        "r15",
743     "r16",        "r17",        "r18",        "r19",
744     "r20",        "r21",        "r22",        "r23",
745     "et",         "bt",         "gp",         "sp",
746     "fp",         "ea",         "ba",         "ra",
747     "status",     "estatus",    "bstatus",    "ienable",
748     "ipending",   "cpuid",      "reserved0",  "exception",
749     "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
750     "badaddr",    "config",     "mpubase",    "mpuacc",
751     "reserved2",  "reserved3",  "reserved4",  "reserved5",
752     "reserved6",  "reserved7",  "reserved8",  "reserved9",
753     "reserved10", "reserved11", "reserved12", "reserved13",
754     "reserved14", "reserved15", "reserved16", "reserved17",
755     "rpc"
756 };
757 
758 #include "exec/gen-icount.h"
759 
760 static void gen_exception(DisasContext *dc, uint32_t excp)
761 {
762     TCGv_i32 tmp = tcg_const_i32(excp);
763 
764     tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
765     gen_helper_raise_exception(cpu_env, tmp);
766     tcg_temp_free_i32(tmp);
767     dc->base.is_jmp = DISAS_NORETURN;
768 }
769 
770 /* generate intermediate code for basic block 'tb'.  */
771 static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
772 {
773     DisasContext *dc = container_of(dcbase, DisasContext, base);
774     CPUNios2State *env = cs->env_ptr;
775     int page_insns;
776 
777     dc->mem_idx = cpu_mmu_index(env, false);
778 
779     /* Bound the number of insns to execute to those left on the page.  */
780     page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
781     dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
782 }
783 
784 static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
785 {
786 }
787 
788 static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
789 {
790     tcg_gen_insn_start(dcbase->pc_next);
791 }
792 
793 static bool nios2_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
794                                       const CPUBreakpoint *bp)
795 {
796     DisasContext *dc = container_of(dcbase, DisasContext, base);
797 
798     gen_exception(dc, EXCP_DEBUG);
799     /*
800      * The address covered by the breakpoint must be included in
801      * [tb->pc, tb->pc + tb->size) in order to for it to be
802      * properly cleared -- thus we increment the PC here so that
803      * the logic setting tb->size below does the right thing.
804      */
805     dc->base.pc_next += 4;
806     return true;
807 }
808 
809 static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
810 {
811     DisasContext *dc = container_of(dcbase, DisasContext, base);
812     CPUNios2State *env = cs->env_ptr;
813     const Nios2Instruction *instr;
814     uint32_t code, pc;
815     uint8_t op;
816 
817     pc = dc->base.pc_next;
818     dc->pc = pc;
819     dc->base.pc_next = pc + 4;
820 
821     /* Decode an instruction */
822 
823 #if defined(CONFIG_USER_ONLY)
824     /* FIXME: Is this needed ? */
825     if (pc >= 0x1000 && pc < 0x2000) {
826         t_gen_helper_raise_exception(dc, 0xaa);
827         return;
828     }
829 #endif
830 
831     code = cpu_ldl_code(env, pc);
832     op = get_opcode(code);
833 
834     if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
835         t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
836         return;
837     }
838 
839     dc->zero = NULL;
840 
841     instr = &i_type_instructions[op];
842     instr->handler(dc, code, instr->flags);
843 
844     if (dc->zero) {
845         tcg_temp_free(dc->zero);
846     }
847 }
848 
849 static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
850 {
851     DisasContext *dc = container_of(dcbase, DisasContext, base);
852 
853     /* Indicate where the next block should start */
854     switch (dc->base.is_jmp) {
855     case DISAS_TOO_MANY:
856     case DISAS_UPDATE:
857         /* Save the current PC back into the CPU register */
858         tcg_gen_movi_tl(cpu_R[R_PC], dc->base.pc_next);
859         tcg_gen_exit_tb(NULL, 0);
860         break;
861 
862     case DISAS_JUMP:
863         /* The jump will already have updated the PC register */
864         tcg_gen_exit_tb(NULL, 0);
865         break;
866 
867     case DISAS_NORETURN:
868         /* nothing more to generate */
869         break;
870 
871     default:
872         g_assert_not_reached();
873     }
874 }
875 
876 static void nios2_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
877 {
878     qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
879     log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
880 }
881 
882 static const TranslatorOps nios2_tr_ops = {
883     .init_disas_context = nios2_tr_init_disas_context,
884     .tb_start           = nios2_tr_tb_start,
885     .insn_start         = nios2_tr_insn_start,
886     .breakpoint_check   = nios2_tr_breakpoint_check,
887     .translate_insn     = nios2_tr_translate_insn,
888     .tb_stop            = nios2_tr_tb_stop,
889     .disas_log          = nios2_tr_disas_log,
890 };
891 
892 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
893 {
894     DisasContext dc;
895     translator_loop(&nios2_tr_ops, &dc.base, cs, tb, max_insns);
896 }
897 
898 void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
899 {
900     Nios2CPU *cpu = NIOS2_CPU(cs);
901     CPUNios2State *env = &cpu->env;
902     int i;
903 
904     if (!env) {
905         return;
906     }
907 
908     qemu_fprintf(f, "IN: PC=%x %s\n",
909                  env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
910 
911     for (i = 0; i < NUM_CORE_REGS; i++) {
912         qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
913         if ((i + 1) % 4 == 0) {
914             qemu_fprintf(f, "\n");
915         }
916     }
917 #if !defined(CONFIG_USER_ONLY)
918     qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
919                  env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
920                  (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
921                  env->mmu.tlbacc_wr);
922 #endif
923     qemu_fprintf(f, "\n\n");
924 }
925 
926 void nios2_tcg_init(void)
927 {
928     int i;
929 
930     for (i = 0; i < NUM_CORE_REGS; i++) {
931         cpu_R[i] = tcg_global_mem_new(cpu_env,
932                                       offsetof(CPUNios2State, regs[i]),
933                                       regnames[i]);
934     }
935 }
936 
937 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
938                           target_ulong *data)
939 {
940     env->regs[R_PC] = data[0];
941 }
942