xref: /openbmc/qemu/target/nios2/translate.c (revision 94452ac4)
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 #include "semihosting/semihost.h"
37 
38 /* is_jmp field values */
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 typedef struct {
56     uint8_t op;
57     union {
58         uint16_t u;
59         int16_t s;
60     } imm16;
61     uint8_t b;
62     uint8_t a;
63 } InstrIType;
64 
65 #define I_TYPE(instr, code)                \
66     InstrIType (instr) = {                 \
67         .op    = extract32((code), 0, 6),  \
68         .imm16.u = extract32((code), 6, 16), \
69         .b     = extract32((code), 22, 5), \
70         .a     = extract32((code), 27, 5), \
71     }
72 
73 typedef target_ulong ImmFromIType(const InstrIType *);
74 
75 static target_ulong imm_unsigned(const InstrIType *i)
76 {
77     return i->imm16.u;
78 }
79 
80 static target_ulong imm_signed(const InstrIType *i)
81 {
82     return i->imm16.s;
83 }
84 
85 static target_ulong imm_shifted(const InstrIType *i)
86 {
87     return i->imm16.u << 16;
88 }
89 
90 /* R-Type instruction parsing */
91 typedef struct {
92     uint8_t op;
93     uint8_t imm5;
94     uint8_t opx;
95     uint8_t c;
96     uint8_t b;
97     uint8_t a;
98 } InstrRType;
99 
100 #define R_TYPE(instr, code)                \
101     InstrRType (instr) = {                 \
102         .op    = extract32((code), 0, 6),  \
103         .imm5  = extract32((code), 6, 5),  \
104         .opx   = extract32((code), 11, 6), \
105         .c     = extract32((code), 17, 5), \
106         .b     = extract32((code), 22, 5), \
107         .a     = extract32((code), 27, 5), \
108     }
109 
110 /* J-Type instruction parsing */
111 typedef struct {
112     uint8_t op;
113     uint32_t imm26;
114 } InstrJType;
115 
116 #define J_TYPE(instr, code)                \
117     InstrJType (instr) = {                 \
118         .op    = extract32((code), 0, 6),  \
119         .imm26 = extract32((code), 6, 26), \
120     }
121 
122 typedef void GenFn2i(TCGv, TCGv, target_long);
123 typedef void GenFn3(TCGv, TCGv, TCGv);
124 typedef void GenFn4(TCGv, TCGv, TCGv, TCGv);
125 
126 typedef struct DisasContext {
127     DisasContextBase  base;
128     target_ulong      pc;
129     int               mem_idx;
130     uint32_t          tb_flags;
131     TCGv              sink;
132     const ControlRegState *cr_state;
133     bool              eic_present;
134 } DisasContext;
135 
136 static TCGv cpu_R[NUM_GP_REGS];
137 static TCGv cpu_pc;
138 #ifndef CONFIG_USER_ONLY
139 static TCGv cpu_crs_R[NUM_GP_REGS];
140 #endif
141 
142 typedef struct Nios2Instruction {
143     void     (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
144     uint32_t  flags;
145 } Nios2Instruction;
146 
147 static uint8_t get_opcode(uint32_t code)
148 {
149     I_TYPE(instr, code);
150     return instr.op;
151 }
152 
153 static uint8_t get_opxcode(uint32_t code)
154 {
155     R_TYPE(instr, code);
156     return instr.opx;
157 }
158 
159 static TCGv load_gpr(DisasContext *dc, unsigned reg)
160 {
161     assert(reg < NUM_GP_REGS);
162 
163     /*
164      * With shadow register sets, register r0 does not necessarily contain 0,
165      * but it is overwhelmingly likely that it does -- software is supposed
166      * to have set r0 to 0 in every shadow register set before use.
167      */
168     if (unlikely(reg == R_ZERO) && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
169         return tcg_constant_tl(0);
170     }
171     if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
172         return cpu_R[reg];
173     }
174 #ifdef CONFIG_USER_ONLY
175     g_assert_not_reached();
176 #else
177     return cpu_crs_R[reg];
178 #endif
179 }
180 
181 static TCGv dest_gpr(DisasContext *dc, unsigned reg)
182 {
183     assert(reg < NUM_GP_REGS);
184 
185     /*
186      * The spec for shadow register sets isn't clear, but we assume that
187      * writes to r0 are discarded regardless of CRS.
188      */
189     if (unlikely(reg == R_ZERO)) {
190         if (dc->sink == NULL) {
191             dc->sink = tcg_temp_new();
192         }
193         return dc->sink;
194     }
195     if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
196         return cpu_R[reg];
197     }
198 #ifdef CONFIG_USER_ONLY
199     g_assert_not_reached();
200 #else
201     return cpu_crs_R[reg];
202 #endif
203 }
204 
205 static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
206 {
207     /* Note that PC is advanced for all hardware exceptions. */
208     tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
209     gen_helper_raise_exception(cpu_env, tcg_constant_i32(index));
210     dc->base.is_jmp = DISAS_NORETURN;
211 }
212 
213 static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
214 {
215     const TranslationBlock *tb = dc->base.tb;
216 
217     if (translator_use_goto_tb(&dc->base, dest)) {
218         tcg_gen_goto_tb(n);
219         tcg_gen_movi_tl(cpu_pc, dest);
220         tcg_gen_exit_tb(tb, n);
221     } else {
222         tcg_gen_movi_tl(cpu_pc, dest);
223         tcg_gen_lookup_and_goto_ptr();
224     }
225     dc->base.is_jmp = DISAS_NORETURN;
226 }
227 
228 static void gen_jumpr(DisasContext *dc, int regno, bool is_call)
229 {
230     TCGLabel *l = gen_new_label();
231     TCGv test = tcg_temp_new();
232     TCGv dest = load_gpr(dc, regno);
233 
234     tcg_gen_andi_tl(test, dest, 3);
235     tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l);
236     tcg_temp_free(test);
237 
238     tcg_gen_mov_tl(cpu_pc, dest);
239     if (is_call) {
240         tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
241     }
242     tcg_gen_lookup_and_goto_ptr();
243 
244     gen_set_label(l);
245     tcg_gen_st_tl(dest, cpu_env, offsetof(CPUNios2State, ctrl[CR_BADADDR]));
246     t_gen_helper_raise_exception(dc, EXCP_UNALIGND);
247 
248     dc->base.is_jmp = DISAS_NORETURN;
249 }
250 
251 static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
252 {
253     t_gen_helper_raise_exception(dc, flags);
254 }
255 
256 static bool gen_check_supervisor(DisasContext *dc)
257 {
258     if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) {
259         /* CPU in user mode, privileged instruction called, stop. */
260         t_gen_helper_raise_exception(dc, EXCP_SUPERI);
261         return false;
262     }
263     return true;
264 }
265 
266 /*
267  * Used as a placeholder for all instructions which do not have
268  * an effect on the simulator (e.g. flush, sync)
269  */
270 static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
271 {
272     /* Nothing to do here */
273 }
274 
275 /*
276  * J-Type instructions
277  */
278 static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
279 {
280     J_TYPE(instr, code);
281     gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
282 }
283 
284 static void call(DisasContext *dc, uint32_t code, uint32_t flags)
285 {
286     tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
287     jmpi(dc, code, flags);
288 }
289 
290 /*
291  * I-Type instructions
292  */
293 /* Load instructions */
294 static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
295 {
296     I_TYPE(instr, code);
297 
298     TCGv addr = tcg_temp_new();
299     TCGv data = dest_gpr(dc, instr.b);
300 
301     tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
302     tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
303     tcg_temp_free(addr);
304 }
305 
306 /* Store instructions */
307 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
308 {
309     I_TYPE(instr, code);
310     TCGv val = load_gpr(dc, instr.b);
311 
312     TCGv addr = tcg_temp_new();
313     tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
314     tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
315     tcg_temp_free(addr);
316 }
317 
318 /* Branch instructions */
319 static void br(DisasContext *dc, uint32_t code, uint32_t flags)
320 {
321     I_TYPE(instr, code);
322 
323     gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4));
324 }
325 
326 static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
327 {
328     I_TYPE(instr, code);
329 
330     TCGLabel *l1 = gen_new_label();
331     tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1);
332     gen_goto_tb(dc, 0, dc->base.pc_next);
333     gen_set_label(l1);
334     gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
335 }
336 
337 /* Comparison instructions */
338 static void do_i_cmpxx(DisasContext *dc, uint32_t insn,
339                        TCGCond cond, ImmFromIType *imm)
340 {
341     I_TYPE(instr, insn);
342     tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b),
343                         load_gpr(dc, instr.a), imm(&instr));
344 }
345 
346 #define gen_i_cmpxx(fname, imm)                                             \
347     static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
348     { do_i_cmpxx(dc, code, flags, imm); }
349 
350 gen_i_cmpxx(gen_cmpxxsi, imm_signed)
351 gen_i_cmpxx(gen_cmpxxui, imm_unsigned)
352 
353 /* Math/logic instructions */
354 static void do_i_math_logic(DisasContext *dc, uint32_t insn,
355                             GenFn2i *fn, ImmFromIType *imm,
356                             bool x_op_0_eq_x)
357 {
358     I_TYPE(instr, insn);
359     target_ulong val;
360 
361     if (unlikely(instr.b == R_ZERO)) {
362         /* Store to R_ZERO is ignored -- this catches the canonical NOP. */
363         return;
364     }
365 
366     val = imm(&instr);
367 
368     if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
369         /* This catches the canonical expansions of movi and movhi. */
370         tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0);
371     } else {
372         fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val);
373     }
374 }
375 
376 #define gen_i_math_logic(fname, insn, x_op_0, imm)                          \
377     static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
378     { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); }
379 
380 gen_i_math_logic(addi,  addi, 1, imm_signed)
381 gen_i_math_logic(muli,  muli, 0, imm_signed)
382 
383 gen_i_math_logic(andi,  andi, 0, imm_unsigned)
384 gen_i_math_logic(ori,   ori,  1, imm_unsigned)
385 gen_i_math_logic(xori,  xori, 1, imm_unsigned)
386 
387 gen_i_math_logic(andhi, andi, 0, imm_shifted)
388 gen_i_math_logic(orhi , ori,  1, imm_shifted)
389 gen_i_math_logic(xorhi, xori, 1, imm_shifted)
390 
391 /* rB <- prs.rA + sigma(IMM16) */
392 static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags)
393 {
394     if (!dc->eic_present) {
395         t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
396         return;
397     }
398     if (!gen_check_supervisor(dc)) {
399         return;
400     }
401 
402 #ifdef CONFIG_USER_ONLY
403     g_assert_not_reached();
404 #else
405     I_TYPE(instr, code);
406     TCGv dest = dest_gpr(dc, instr.b);
407     gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a));
408     tcg_gen_addi_tl(dest, dest, instr.imm16.s);
409 #endif
410 }
411 
412 /* Prototype only, defined below */
413 static void handle_r_type_instr(DisasContext *dc, uint32_t code,
414                                 uint32_t flags);
415 
416 static const Nios2Instruction i_type_instructions[] = {
417     INSTRUCTION(call),                                /* call */
418     INSTRUCTION(jmpi),                                /* jmpi */
419     INSTRUCTION_ILLEGAL(),
420     INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbu */
421     INSTRUCTION(addi),                                /* addi */
422     INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stb */
423     INSTRUCTION(br),                                  /* br */
424     INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldb */
425     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE),        /* cmpgei */
426     INSTRUCTION_ILLEGAL(),
427     INSTRUCTION_ILLEGAL(),
428     INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhu */
429     INSTRUCTION(andi),                                /* andi */
430     INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sth */
431     INSTRUCTION_FLG(gen_bxx, TCG_COND_GE),            /* bge */
432     INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldh */
433     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT),        /* cmplti */
434     INSTRUCTION_ILLEGAL(),
435     INSTRUCTION_ILLEGAL(),
436     INSTRUCTION_NOP(),                                /* initda */
437     INSTRUCTION(ori),                                 /* ori */
438     INSTRUCTION_FLG(gen_stx, MO_UL),                  /* stw */
439     INSTRUCTION_FLG(gen_bxx, TCG_COND_LT),            /* blt */
440     INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldw */
441     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE),        /* cmpnei */
442     INSTRUCTION_ILLEGAL(),
443     INSTRUCTION_ILLEGAL(),
444     INSTRUCTION_NOP(),                                /* flushda */
445     INSTRUCTION(xori),                                /* xori */
446     INSTRUCTION_ILLEGAL(),
447     INSTRUCTION_FLG(gen_bxx, TCG_COND_NE),            /* bne */
448     INSTRUCTION_ILLEGAL(),
449     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ),        /* cmpeqi */
450     INSTRUCTION_ILLEGAL(),
451     INSTRUCTION_ILLEGAL(),
452     INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbuio */
453     INSTRUCTION(muli),                                /* muli */
454     INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stbio */
455     INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ),            /* beq */
456     INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldbio */
457     INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU),       /* cmpgeui */
458     INSTRUCTION_ILLEGAL(),
459     INSTRUCTION_ILLEGAL(),
460     INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhuio */
461     INSTRUCTION(andhi),                               /* andhi */
462     INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sthio */
463     INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU),           /* bgeu */
464     INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldhio */
465     INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU),       /* cmpltui */
466     INSTRUCTION_ILLEGAL(),
467     INSTRUCTION_UNIMPLEMENTED(),                      /* custom */
468     INSTRUCTION_NOP(),                                /* initd */
469     INSTRUCTION(orhi),                                /* orhi */
470     INSTRUCTION_FLG(gen_stx, MO_SL),                  /* stwio */
471     INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU),           /* bltu */
472     INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldwio */
473     INSTRUCTION(rdprs),                               /* rdprs */
474     INSTRUCTION_ILLEGAL(),
475     INSTRUCTION_FLG(handle_r_type_instr, 0),          /* R-Type */
476     INSTRUCTION_NOP(),                                /* flushd */
477     INSTRUCTION(xorhi),                               /* xorhi */
478     INSTRUCTION_ILLEGAL(),
479     INSTRUCTION_ILLEGAL(),
480     INSTRUCTION_ILLEGAL(),
481 };
482 
483 /*
484  * R-Type instructions
485  */
486 /*
487  * status <- estatus
488  * PC <- ea
489  */
490 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
491 {
492     if (!gen_check_supervisor(dc)) {
493         return;
494     }
495 
496 #ifdef CONFIG_USER_ONLY
497     g_assert_not_reached();
498 #else
499     if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
500         TCGv tmp = tcg_temp_new();
501         tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS]));
502         gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_EA));
503         tcg_temp_free(tmp);
504     } else {
505         gen_helper_eret(cpu_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA));
506     }
507     dc->base.is_jmp = DISAS_NORETURN;
508 #endif
509 }
510 
511 /* PC <- ra */
512 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
513 {
514     gen_jumpr(dc, R_RA, false);
515 }
516 
517 /*
518  * status <- bstatus
519  * PC <- ba
520  */
521 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
522 {
523     if (!gen_check_supervisor(dc)) {
524         return;
525     }
526 
527 #ifdef CONFIG_USER_ONLY
528     g_assert_not_reached();
529 #else
530     TCGv tmp = tcg_temp_new();
531     tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS]));
532     gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_BA));
533     tcg_temp_free(tmp);
534 
535     dc->base.is_jmp = DISAS_NORETURN;
536 #endif
537 }
538 
539 /* PC <- rA */
540 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
541 {
542     R_TYPE(instr, code);
543 
544     gen_jumpr(dc, instr.a, false);
545 }
546 
547 /* rC <- PC + 4 */
548 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
549 {
550     R_TYPE(instr, code);
551 
552     tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next);
553 }
554 
555 /*
556  * ra <- PC + 4
557  * PC <- rA
558  */
559 static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
560 {
561     R_TYPE(instr, code);
562 
563     gen_jumpr(dc, instr.a, true);
564 }
565 
566 /* rC <- ctlN */
567 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
568 {
569     if (!gen_check_supervisor(dc)) {
570         return;
571     }
572 
573 #ifdef CONFIG_USER_ONLY
574     g_assert_not_reached();
575 #else
576     R_TYPE(instr, code);
577     TCGv t1, t2, dest = dest_gpr(dc, instr.c);
578 
579     /* Reserved registers read as zero. */
580     if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
581         tcg_gen_movi_tl(dest, 0);
582         return;
583     }
584 
585     switch (instr.imm5) {
586     case CR_IPENDING:
587         /*
588          * The value of the ipending register is synthetic.
589          * In hw, this is the AND of a set of hardware irq lines
590          * with the ienable register.  In qemu, we re-use the space
591          * of CR_IPENDING to store the set of irq lines, and so we
592          * must perform the AND here, and anywhere else we need the
593          * guest value of ipending.
594          */
595         t1 = tcg_temp_new();
596         t2 = tcg_temp_new();
597         tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ctrl[CR_IPENDING]));
598         tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ctrl[CR_IENABLE]));
599         tcg_gen_and_tl(dest, t1, t2);
600         tcg_temp_free(t1);
601         tcg_temp_free(t2);
602         break;
603     default:
604         tcg_gen_ld_tl(dest, cpu_env,
605                       offsetof(CPUNios2State, ctrl[instr.imm5]));
606         break;
607     }
608 #endif
609 }
610 
611 /* ctlN <- rA */
612 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
613 {
614     if (!gen_check_supervisor(dc)) {
615         return;
616     }
617 
618 #ifdef CONFIG_USER_ONLY
619     g_assert_not_reached();
620 #else
621     R_TYPE(instr, code);
622     TCGv v = load_gpr(dc, instr.a);
623     uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]);
624     uint32_t wr = dc->cr_state[instr.imm5].writable;
625     uint32_t ro = dc->cr_state[instr.imm5].readonly;
626 
627     /* Skip reserved or readonly registers. */
628     if (wr == 0) {
629         return;
630     }
631 
632     switch (instr.imm5) {
633     case CR_PTEADDR:
634         gen_helper_mmu_write_pteaddr(cpu_env, v);
635         break;
636     case CR_TLBACC:
637         gen_helper_mmu_write_tlbacc(cpu_env, v);
638         break;
639     case CR_TLBMISC:
640         gen_helper_mmu_write_tlbmisc(cpu_env, v);
641         break;
642     case CR_STATUS:
643     case CR_IENABLE:
644         /* If interrupts were enabled using WRCTL, trigger them. */
645         dc->base.is_jmp = DISAS_UPDATE;
646         /* fall through */
647     default:
648         if (wr == -1) {
649             /* The register is entirely writable. */
650             tcg_gen_st_tl(v, cpu_env, ofs);
651         } else {
652             /*
653              * The register is partially read-only or reserved:
654              * merge the value.
655              */
656             TCGv n = tcg_temp_new();
657 
658             tcg_gen_andi_tl(n, v, wr);
659 
660             if (ro != 0) {
661                 TCGv o = tcg_temp_new();
662                 tcg_gen_ld_tl(o, cpu_env, ofs);
663                 tcg_gen_andi_tl(o, o, ro);
664                 tcg_gen_or_tl(n, n, o);
665                 tcg_temp_free(o);
666             }
667 
668             tcg_gen_st_tl(n, cpu_env, ofs);
669             tcg_temp_free(n);
670         }
671         break;
672     }
673 #endif
674 }
675 
676 /* prs.rC <- rA */
677 static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags)
678 {
679     if (!dc->eic_present) {
680         t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
681         return;
682     }
683     if (!gen_check_supervisor(dc)) {
684         return;
685     }
686 
687 #ifdef CONFIG_USER_ONLY
688     g_assert_not_reached();
689 #else
690     R_TYPE(instr, code);
691     gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c),
692                      load_gpr(dc, instr.a));
693     /*
694      * The expected write to PRS[r0] is 0, from CRS[r0].
695      * If not, and CRS == PRS (which we cannot tell from here),
696      * we may now have a non-zero value in our current r0.
697      * By ending the TB, we re-evaluate tb_flags and find out.
698      */
699     if (instr.c == 0
700         && (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) {
701         dc->base.is_jmp = DISAS_UPDATE;
702     }
703 #endif
704 }
705 
706 /* Comparison instructions */
707 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
708 {
709     R_TYPE(instr, code);
710     tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c),
711                        load_gpr(dc, instr.a), load_gpr(dc, instr.b));
712 }
713 
714 /* Math/logic instructions */
715 static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn)
716 {
717     R_TYPE(instr, insn);
718     fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5);
719 }
720 
721 static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn)
722 {
723     R_TYPE(instr, insn);
724     fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b));
725 }
726 
727 #define gen_ri_math_logic(fname, insn)                                      \
728     static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
729     { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); }
730 
731 #define gen_rr_math_logic(fname, insn)                                      \
732     static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
733     { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); }
734 
735 gen_rr_math_logic(add,  add)
736 gen_rr_math_logic(sub,  sub)
737 gen_rr_math_logic(mul,  mul)
738 
739 gen_rr_math_logic(and,  and)
740 gen_rr_math_logic(or,   or)
741 gen_rr_math_logic(xor,  xor)
742 gen_rr_math_logic(nor,  nor)
743 
744 gen_ri_math_logic(srai, sari)
745 gen_ri_math_logic(srli, shri)
746 gen_ri_math_logic(slli, shli)
747 gen_ri_math_logic(roli, rotli)
748 
749 static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn)
750 {
751     R_TYPE(instr, insn);
752     TCGv discard = tcg_temp_new();
753 
754     fn(discard, dest_gpr(dc, instr.c),
755        load_gpr(dc, instr.a), load_gpr(dc, instr.b));
756     tcg_temp_free(discard);
757 }
758 
759 #define gen_rr_mul_high(fname, insn)                                        \
760     static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
761     { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); }
762 
763 gen_rr_mul_high(mulxss, muls2)
764 gen_rr_mul_high(mulxuu, mulu2)
765 gen_rr_mul_high(mulxsu, mulsu2)
766 
767 static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn)
768 {
769     R_TYPE(instr, insn);
770     TCGv sh = tcg_temp_new();
771 
772     tcg_gen_andi_tl(sh, load_gpr(dc, instr.b), 31);
773     fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), sh);
774     tcg_temp_free(sh);
775 }
776 
777 #define gen_rr_shift(fname, insn)                                           \
778     static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
779     { do_rr_shift(dc, code, tcg_gen_##insn##_tl); }
780 
781 gen_rr_shift(sra, sar)
782 gen_rr_shift(srl, shr)
783 gen_rr_shift(sll, shl)
784 gen_rr_shift(rol, rotl)
785 gen_rr_shift(ror, rotr)
786 
787 static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
788 {
789     R_TYPE(instr, (code));
790     gen_helper_divs(dest_gpr(dc, instr.c), cpu_env,
791                     load_gpr(dc, instr.a), load_gpr(dc, instr.b));
792 }
793 
794 static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
795 {
796     R_TYPE(instr, (code));
797     gen_helper_divu(dest_gpr(dc, instr.c), cpu_env,
798                     load_gpr(dc, instr.a), load_gpr(dc, instr.b));
799 }
800 
801 static void trap(DisasContext *dc, uint32_t code, uint32_t flags)
802 {
803 #ifdef CONFIG_USER_ONLY
804     /*
805      * The imm5 field is not stored anywhere on real hw; the kernel
806      * has to load the insn and extract the field.  But we can make
807      * things easier for cpu_loop if we pop this into env->error_code.
808      */
809     R_TYPE(instr, code);
810     tcg_gen_st_i32(tcg_constant_i32(instr.imm5), cpu_env,
811                    offsetof(CPUNios2State, error_code));
812 #endif
813     t_gen_helper_raise_exception(dc, EXCP_TRAP);
814 }
815 
816 static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags)
817 {
818 #ifndef CONFIG_USER_ONLY
819     /* The semihosting instruction is "break 1".  */
820     bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U);
821     R_TYPE(instr, code);
822     if (semihosting_enabled(is_user) && instr.imm5 == 1) {
823         t_gen_helper_raise_exception(dc, EXCP_SEMIHOST);
824         return;
825     }
826 #endif
827 
828     t_gen_helper_raise_exception(dc, EXCP_BREAK);
829 }
830 
831 static const Nios2Instruction r_type_instructions[] = {
832     INSTRUCTION_ILLEGAL(),
833     INSTRUCTION(eret),                                /* eret */
834     INSTRUCTION(roli),                                /* roli */
835     INSTRUCTION(rol),                                 /* rol */
836     INSTRUCTION_NOP(),                                /* flushp */
837     INSTRUCTION(ret),                                 /* ret */
838     INSTRUCTION(nor),                                 /* nor */
839     INSTRUCTION(mulxuu),                              /* mulxuu */
840     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),          /* cmpge */
841     INSTRUCTION(bret),                                /* bret */
842     INSTRUCTION_ILLEGAL(),
843     INSTRUCTION(ror),                                 /* ror */
844     INSTRUCTION_NOP(),                                /* flushi */
845     INSTRUCTION(jmp),                                 /* jmp */
846     INSTRUCTION(and),                                 /* and */
847     INSTRUCTION_ILLEGAL(),
848     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),          /* cmplt */
849     INSTRUCTION_ILLEGAL(),
850     INSTRUCTION(slli),                                /* slli */
851     INSTRUCTION(sll),                                 /* sll */
852     INSTRUCTION(wrprs),                               /* wrprs */
853     INSTRUCTION_ILLEGAL(),
854     INSTRUCTION(or),                                  /* or */
855     INSTRUCTION(mulxsu),                              /* mulxsu */
856     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),          /* cmpne */
857     INSTRUCTION_ILLEGAL(),
858     INSTRUCTION(srli),                                /* srli */
859     INSTRUCTION(srl),                                 /* srl */
860     INSTRUCTION(nextpc),                              /* nextpc */
861     INSTRUCTION(callr),                               /* callr */
862     INSTRUCTION(xor),                                 /* xor */
863     INSTRUCTION(mulxss),                              /* mulxss */
864     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),          /* cmpeq */
865     INSTRUCTION_ILLEGAL(),
866     INSTRUCTION_ILLEGAL(),
867     INSTRUCTION_ILLEGAL(),
868     INSTRUCTION(divu),                                /* divu */
869     INSTRUCTION(divs),                                /* div */
870     INSTRUCTION(rdctl),                               /* rdctl */
871     INSTRUCTION(mul),                                 /* mul */
872     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),         /* cmpgeu */
873     INSTRUCTION_NOP(),                                /* initi */
874     INSTRUCTION_ILLEGAL(),
875     INSTRUCTION_ILLEGAL(),
876     INSTRUCTION_ILLEGAL(),
877     INSTRUCTION(trap),                                /* trap */
878     INSTRUCTION(wrctl),                               /* wrctl */
879     INSTRUCTION_ILLEGAL(),
880     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),         /* cmpltu */
881     INSTRUCTION(add),                                 /* add */
882     INSTRUCTION_ILLEGAL(),
883     INSTRUCTION_ILLEGAL(),
884     INSTRUCTION(gen_break),                           /* break */
885     INSTRUCTION_ILLEGAL(),
886     INSTRUCTION(nop),                                 /* nop */
887     INSTRUCTION_ILLEGAL(),
888     INSTRUCTION_ILLEGAL(),
889     INSTRUCTION(sub),                                 /* sub */
890     INSTRUCTION(srai),                                /* srai */
891     INSTRUCTION(sra),                                 /* sra */
892     INSTRUCTION_ILLEGAL(),
893     INSTRUCTION_ILLEGAL(),
894     INSTRUCTION_ILLEGAL(),
895     INSTRUCTION_ILLEGAL(),
896 };
897 
898 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
899 {
900     uint8_t opx;
901     const Nios2Instruction *instr;
902 
903     opx = get_opxcode(code);
904     if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
905         goto illegal_op;
906     }
907 
908     instr = &r_type_instructions[opx];
909     instr->handler(dc, code, instr->flags);
910 
911     return;
912 
913 illegal_op:
914     t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
915 }
916 
917 static const char * const gr_regnames[NUM_GP_REGS] = {
918     "zero",       "at",         "r2",         "r3",
919     "r4",         "r5",         "r6",         "r7",
920     "r8",         "r9",         "r10",        "r11",
921     "r12",        "r13",        "r14",        "r15",
922     "r16",        "r17",        "r18",        "r19",
923     "r20",        "r21",        "r22",        "r23",
924     "et",         "bt",         "gp",         "sp",
925     "fp",         "ea",         "ba",         "ra",
926 };
927 
928 #ifndef CONFIG_USER_ONLY
929 static const char * const cr_regnames[NUM_CR_REGS] = {
930     "status",     "estatus",    "bstatus",    "ienable",
931     "ipending",   "cpuid",      "res6",       "exception",
932     "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
933     "badaddr",    "config",     "mpubase",    "mpuacc",
934     "res16",      "res17",      "res18",      "res19",
935     "res20",      "res21",      "res22",      "res23",
936     "res24",      "res25",      "res26",      "res27",
937     "res28",      "res29",      "res30",      "res31",
938 };
939 #endif
940 
941 #include "exec/gen-icount.h"
942 
943 /* generate intermediate code for basic block 'tb'.  */
944 static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
945 {
946     DisasContext *dc = container_of(dcbase, DisasContext, base);
947     CPUNios2State *env = cs->env_ptr;
948     Nios2CPU *cpu = env_archcpu(env);
949     int page_insns;
950 
951     dc->mem_idx = cpu_mmu_index(env, false);
952     dc->cr_state = cpu->cr_state;
953     dc->tb_flags = dc->base.tb->flags;
954     dc->eic_present = cpu->eic_present;
955 
956     /* Bound the number of insns to execute to those left on the page.  */
957     page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
958     dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
959 }
960 
961 static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
962 {
963 }
964 
965 static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
966 {
967     tcg_gen_insn_start(dcbase->pc_next);
968 }
969 
970 static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
971 {
972     DisasContext *dc = container_of(dcbase, DisasContext, base);
973     CPUNios2State *env = cs->env_ptr;
974     const Nios2Instruction *instr;
975     uint32_t code, pc;
976     uint8_t op;
977 
978     pc = dc->base.pc_next;
979     dc->pc = pc;
980     dc->base.pc_next = pc + 4;
981 
982     /* Decode an instruction */
983     code = cpu_ldl_code(env, pc);
984     op = get_opcode(code);
985 
986     if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
987         t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
988         return;
989     }
990 
991     dc->sink = NULL;
992 
993     instr = &i_type_instructions[op];
994     instr->handler(dc, code, instr->flags);
995 
996     if (dc->sink) {
997         tcg_temp_free(dc->sink);
998     }
999 }
1000 
1001 static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
1002 {
1003     DisasContext *dc = container_of(dcbase, DisasContext, base);
1004 
1005     /* Indicate where the next block should start */
1006     switch (dc->base.is_jmp) {
1007     case DISAS_TOO_MANY:
1008         gen_goto_tb(dc, 0, dc->base.pc_next);
1009         break;
1010 
1011     case DISAS_UPDATE:
1012         /* Save the current PC, and return to the main loop. */
1013         tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
1014         tcg_gen_exit_tb(NULL, 0);
1015         break;
1016 
1017     case DISAS_NORETURN:
1018         /* nothing more to generate */
1019         break;
1020 
1021     default:
1022         g_assert_not_reached();
1023     }
1024 }
1025 
1026 static void nios2_tr_disas_log(const DisasContextBase *dcbase,
1027                                CPUState *cpu, FILE *logfile)
1028 {
1029     fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
1030     target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
1031 }
1032 
1033 static const TranslatorOps nios2_tr_ops = {
1034     .init_disas_context = nios2_tr_init_disas_context,
1035     .tb_start           = nios2_tr_tb_start,
1036     .insn_start         = nios2_tr_insn_start,
1037     .translate_insn     = nios2_tr_translate_insn,
1038     .tb_stop            = nios2_tr_tb_stop,
1039     .disas_log          = nios2_tr_disas_log,
1040 };
1041 
1042 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns,
1043                            target_ulong pc, void *host_pc)
1044 {
1045     DisasContext dc;
1046     translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base);
1047 }
1048 
1049 void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1050 {
1051     Nios2CPU *cpu = NIOS2_CPU(cs);
1052     CPUNios2State *env = &cpu->env;
1053     int i;
1054 
1055     qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
1056 
1057     for (i = 0; i < NUM_GP_REGS; i++) {
1058         qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]);
1059         if ((i + 1) % 4 == 0) {
1060             qemu_fprintf(f, "\n");
1061         }
1062     }
1063 
1064 #if !defined(CONFIG_USER_ONLY)
1065     int j;
1066 
1067     for (i = j = 0; i < NUM_CR_REGS; i++) {
1068         if (!nios2_cr_reserved(&cpu->cr_state[i])) {
1069             qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
1070             if (++j % 4 == 0) {
1071                 qemu_fprintf(f, "\n");
1072             }
1073         }
1074     }
1075     if (j % 4 != 0) {
1076         qemu_fprintf(f, "\n");
1077     }
1078     if (cpu->mmu_present) {
1079         qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
1080                      env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
1081                      FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
1082                      env->mmu.tlbacc_wr);
1083     }
1084 #endif
1085     qemu_fprintf(f, "\n\n");
1086 }
1087 
1088 void nios2_tcg_init(void)
1089 {
1090 #ifndef CONFIG_USER_ONLY
1091     TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env,
1092                                           offsetof(CPUNios2State, regs), "crs");
1093 
1094     for (int i = 0; i < NUM_GP_REGS; i++) {
1095         cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
1096     }
1097 
1098 #define offsetof_regs0(N)  offsetof(CPUNios2State, shadow_regs[0][N])
1099 #else
1100 #define offsetof_regs0(N)  offsetof(CPUNios2State, regs[N])
1101 #endif
1102 
1103     for (int i = 0; i < NUM_GP_REGS; i++) {
1104         cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i),
1105                                       gr_regnames[i]);
1106     }
1107 
1108 #undef offsetof_regs0
1109 
1110     cpu_pc = tcg_global_mem_new(cpu_env,
1111                                 offsetof(CPUNios2State, pc), "pc");
1112 }
1113 
1114 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
1115                           target_ulong *data)
1116 {
1117     env->pc = data[0];
1118 }
1119