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