]> Git Repo - qemu.git/blob - target/nios2/translate.c
arm/translate-a64: mark path as unreachable to eliminate warning
[qemu.git] / target / nios2 / translate.c
1 /*
2  * Altera Nios II emulation for qemu: main translation routines.
3  *
4  * Copyright (C) 2016 Marek Vasut <[email protected]>
5  * Copyright (C) 2012 Chris Wulff <[email protected]>
6  * Copyright (C) 2010 Tobias Klauser <[email protected]>
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 "cpu.h"
25 #include "tcg-op.h"
26 #include "exec/exec-all.h"
27 #include "disas/disas.h"
28 #include "exec/helper-proto.h"
29 #include "exec/helper-gen.h"
30 #include "exec/log.h"
31 #include "exec/cpu_ldst.h"
32 #include "exec/translator.h"
33
34 /* is_jmp field values */
35 #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
36 #define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
37 #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
38
39 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
40 #define INSTRUCTION(func)                  \
41         INSTRUCTION_FLG(func, 0)
42 #define INSTRUCTION_NOP()                  \
43         INSTRUCTION_FLG(nop, 0)
44 #define INSTRUCTION_UNIMPLEMENTED()        \
45         INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
46 #define INSTRUCTION_ILLEGAL()              \
47         INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
48
49 /* Special R-Type instruction opcode */
50 #define INSN_R_TYPE 0x3A
51
52 /* I-Type instruction parsing */
53 #define I_TYPE(instr, code)                \
54     struct {                               \
55         uint8_t op;                        \
56         union {                            \
57             uint16_t u;                    \
58             int16_t s;                     \
59         } imm16;                           \
60         uint8_t b;                         \
61         uint8_t a;                         \
62     } (instr) = {                          \
63         .op    = extract32((code), 0, 6),  \
64         .imm16.u = extract32((code), 6, 16), \
65         .b     = extract32((code), 22, 5), \
66         .a     = extract32((code), 27, 5), \
67     }
68
69 /* R-Type instruction parsing */
70 #define R_TYPE(instr, code)                \
71     struct {                               \
72         uint8_t op;                        \
73         uint8_t imm5;                      \
74         uint8_t opx;                       \
75         uint8_t c;                         \
76         uint8_t b;                         \
77         uint8_t a;                         \
78     } (instr) = {                          \
79         .op    = extract32((code), 0, 6),  \
80         .imm5  = extract32((code), 6, 5),  \
81         .opx   = extract32((code), 11, 6), \
82         .c     = extract32((code), 17, 5), \
83         .b     = extract32((code), 22, 5), \
84         .a     = extract32((code), 27, 5), \
85     }
86
87 /* J-Type instruction parsing */
88 #define J_TYPE(instr, code)                \
89     struct {                               \
90         uint8_t op;                        \
91         uint32_t imm26;                    \
92     } (instr) = {                          \
93         .op    = extract32((code), 0, 6),  \
94         .imm26 = extract32((code), 6, 26), \
95     }
96
97 typedef struct DisasContext {
98     TCGv_ptr          cpu_env;
99     TCGv             *cpu_R;
100     TCGv_i32          zero;
101     int               is_jmp;
102     target_ulong      pc;
103     TranslationBlock *tb;
104     int               mem_idx;
105     bool              singlestep_enabled;
106 } DisasContext;
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 (TCGV_IS_UNUSED_I32(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 dc->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(dc->cpu_R[R_PC], dc->pc);
148     gen_helper_raise_exception(dc->cpu_env, tmp);
149     tcg_temp_free_i32(tmp);
150     dc->is_jmp = DISAS_UPDATE;
151 }
152
153 static bool use_goto_tb(DisasContext *dc, uint32_t dest)
154 {
155     if (unlikely(dc->singlestep_enabled)) {
156         return false;
157     }
158
159 #ifndef CONFIG_USER_ONLY
160     return (dc->tb->pc & 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     TranslationBlock *tb = dc->tb;
169
170     if (use_goto_tb(dc, dest)) {
171         tcg_gen_goto_tb(n);
172         tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
173         tcg_gen_exit_tb((uintptr_t)tb + n);
174     } else {
175         tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
176         tcg_gen_exit_tb(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->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->is_jmp = DISAS_TB_JUMP;
210 }
211
212 static void call(DisasContext *dc, uint32_t code, uint32_t flags)
213 {
214     tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
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 = dc->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->pc + 4 + (instr.imm16.s & -4));
269     dc->is_jmp = DISAS_TB_JUMP;
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, dc->cpu_R[instr.a], dc->cpu_R[instr.b], l1);
278     gen_goto_tb(dc, 0, dc->pc + 4);
279     gen_set_label(l1);
280     gen_goto_tb(dc, 1, dc->pc + 4 + (instr.imm16.s & -4));
281     dc->is_jmp = DISAS_TB_JUMP;
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, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a],   \
290                         (op3));                                              \
291 }
292
293 gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s)
294 gen_i_cmpxx(gen_cmpxxui, instr.imm16.u)
295
296 /* Math/logic instructions */
297 #define gen_i_math_logic(fname, insn, resimm, op3)                          \
298 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)        \
299 {                                                                           \
300     I_TYPE(instr, (code));                                                  \
301     if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */     \
302         return;                                                             \
303     } else if (instr.a == R_ZERO) { /* MOVxI optimizations */               \
304         tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0);          \
305     } else {                                                                \
306         tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a],     \
307                             (op3));                                         \
308     }                                                                       \
309 }
310
311 gen_i_math_logic(addi,  addi, 1, instr.imm16.s)
312 gen_i_math_logic(muli,  muli, 0, instr.imm16.s)
313
314 gen_i_math_logic(andi,  andi, 0, instr.imm16.u)
315 gen_i_math_logic(ori,   ori,  1, instr.imm16.u)
316 gen_i_math_logic(xori,  xori, 1, instr.imm16.u)
317
318 gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16)
319 gen_i_math_logic(orhi , ori,  1, instr.imm16.u << 16)
320 gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16)
321
322 /* Prototype only, defined below */
323 static void handle_r_type_instr(DisasContext *dc, uint32_t code,
324                                 uint32_t flags);
325
326 static const Nios2Instruction i_type_instructions[] = {
327     INSTRUCTION(call),                                /* call */
328     INSTRUCTION(jmpi),                                /* jmpi */
329     INSTRUCTION_ILLEGAL(),
330     INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbu */
331     INSTRUCTION(addi),                                /* addi */
332     INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stb */
333     INSTRUCTION(br),                                  /* br */
334     INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldb */
335     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE),        /* cmpgei */
336     INSTRUCTION_ILLEGAL(),
337     INSTRUCTION_ILLEGAL(),
338     INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhu */
339     INSTRUCTION(andi),                                /* andi */
340     INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sth */
341     INSTRUCTION_FLG(gen_bxx, TCG_COND_GE),            /* bge */
342     INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldh */
343     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT),        /* cmplti */
344     INSTRUCTION_ILLEGAL(),
345     INSTRUCTION_ILLEGAL(),
346     INSTRUCTION_NOP(),                                /* initda */
347     INSTRUCTION(ori),                                 /* ori */
348     INSTRUCTION_FLG(gen_stx, MO_UL),                  /* stw */
349     INSTRUCTION_FLG(gen_bxx, TCG_COND_LT),            /* blt */
350     INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldw */
351     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE),        /* cmpnei */
352     INSTRUCTION_ILLEGAL(),
353     INSTRUCTION_ILLEGAL(),
354     INSTRUCTION_NOP(),                                /* flushda */
355     INSTRUCTION(xori),                                /* xori */
356     INSTRUCTION_ILLEGAL(),
357     INSTRUCTION_FLG(gen_bxx, TCG_COND_NE),            /* bne */
358     INSTRUCTION_ILLEGAL(),
359     INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ),        /* cmpeqi */
360     INSTRUCTION_ILLEGAL(),
361     INSTRUCTION_ILLEGAL(),
362     INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbuio */
363     INSTRUCTION(muli),                                /* muli */
364     INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stbio */
365     INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ),            /* beq */
366     INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldbio */
367     INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU),       /* cmpgeui */
368     INSTRUCTION_ILLEGAL(),
369     INSTRUCTION_ILLEGAL(),
370     INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhuio */
371     INSTRUCTION(andhi),                               /* andhi */
372     INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sthio */
373     INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU),           /* bgeu */
374     INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldhio */
375     INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU),       /* cmpltui */
376     INSTRUCTION_ILLEGAL(),
377     INSTRUCTION_UNIMPLEMENTED(),                      /* custom */
378     INSTRUCTION_NOP(),                                /* initd */
379     INSTRUCTION(orhi),                                /* orhi */
380     INSTRUCTION_FLG(gen_stx, MO_SL),                  /* stwio */
381     INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU),           /* bltu */
382     INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldwio */
383     INSTRUCTION_UNIMPLEMENTED(),                      /* rdprs */
384     INSTRUCTION_ILLEGAL(),
385     INSTRUCTION_FLG(handle_r_type_instr, 0),          /* R-Type */
386     INSTRUCTION_NOP(),                                /* flushd */
387     INSTRUCTION(xorhi),                               /* xorhi */
388     INSTRUCTION_ILLEGAL(),
389     INSTRUCTION_ILLEGAL(),
390     INSTRUCTION_ILLEGAL(),
391 };
392
393 /*
394  * R-Type instructions
395  */
396 /*
397  * status <- estatus
398  * PC <- ea
399  */
400 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
401 {
402     tcg_gen_mov_tl(dc->cpu_R[CR_STATUS], dc->cpu_R[CR_ESTATUS]);
403     tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_EA]);
404
405     dc->is_jmp = DISAS_JUMP;
406 }
407
408 /* PC <- ra */
409 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
410 {
411     tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_RA]);
412
413     dc->is_jmp = DISAS_JUMP;
414 }
415
416 /* PC <- ba */
417 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
418 {
419     tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_BA]);
420
421     dc->is_jmp = DISAS_JUMP;
422 }
423
424 /* PC <- rA */
425 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
426 {
427     R_TYPE(instr, code);
428
429     tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
430
431     dc->is_jmp = DISAS_JUMP;
432 }
433
434 /* rC <- PC + 4 */
435 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
436 {
437     R_TYPE(instr, code);
438
439     if (likely(instr.c != R_ZERO)) {
440         tcg_gen_movi_tl(dc->cpu_R[instr.c], dc->pc + 4);
441     }
442 }
443
444 /*
445  * ra <- PC + 4
446  * PC <- rA
447  */
448 static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
449 {
450     R_TYPE(instr, code);
451
452     tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
453     tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
454
455     dc->is_jmp = DISAS_JUMP;
456 }
457
458 /* rC <- ctlN */
459 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
460 {
461     R_TYPE(instr, code);
462
463     gen_check_supervisor(dc);
464
465     switch (instr.imm5 + CR_BASE) {
466     case CR_PTEADDR:
467     case CR_TLBACC:
468     case CR_TLBMISC:
469     {
470 #if !defined(CONFIG_USER_ONLY)
471         if (likely(instr.c != R_ZERO)) {
472             tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
473 #ifdef DEBUG_MMU
474             TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
475             gen_helper_mmu_read_debug(dc->cpu_R[instr.c], dc->cpu_env, tmp);
476             tcg_temp_free_i32(tmp);
477 #endif
478         }
479 #endif
480         break;
481     }
482
483     default:
484         if (likely(instr.c != R_ZERO)) {
485             tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
486         }
487         break;
488     }
489 }
490
491 /* ctlN <- rA */
492 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
493 {
494     R_TYPE(instr, code);
495
496     gen_check_supervisor(dc);
497
498     switch (instr.imm5 + CR_BASE) {
499     case CR_PTEADDR:
500     case CR_TLBACC:
501     case CR_TLBMISC:
502     {
503 #if !defined(CONFIG_USER_ONLY)
504         TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
505         gen_helper_mmu_write(dc->cpu_env, tmp, load_gpr(dc, instr.a));
506         tcg_temp_free_i32(tmp);
507 #endif
508         break;
509     }
510
511     default:
512         tcg_gen_mov_tl(dc->cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a));
513         break;
514     }
515
516     /* If interrupts were enabled using WRCTL, trigger them. */
517 #if !defined(CONFIG_USER_ONLY)
518     if ((instr.imm5 + CR_BASE) == CR_STATUS) {
519         gen_helper_check_interrupts(dc->cpu_env);
520     }
521 #endif
522 }
523
524 /* Comparison instructions */
525 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
526 {
527     R_TYPE(instr, code);
528     if (likely(instr.c != R_ZERO)) {
529         tcg_gen_setcond_tl(flags, dc->cpu_R[instr.c], dc->cpu_R[instr.a],
530                            dc->cpu_R[instr.b]);
531     }
532 }
533
534 /* Math/logic instructions */
535 #define gen_r_math_logic(fname, insn, op3)                                 \
536 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
537 {                                                                          \
538     R_TYPE(instr, (code));                                                 \
539     if (likely(instr.c != R_ZERO)) {                                       \
540         tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a),      \
541                        (op3));                                             \
542     }                                                                      \
543 }
544
545 gen_r_math_logic(add,  add_tl,   load_gpr(dc, instr.b))
546 gen_r_math_logic(sub,  sub_tl,   load_gpr(dc, instr.b))
547 gen_r_math_logic(mul,  mul_tl,   load_gpr(dc, instr.b))
548
549 gen_r_math_logic(and,  and_tl,   load_gpr(dc, instr.b))
550 gen_r_math_logic(or,   or_tl,    load_gpr(dc, instr.b))
551 gen_r_math_logic(xor,  xor_tl,   load_gpr(dc, instr.b))
552 gen_r_math_logic(nor,  nor_tl,   load_gpr(dc, instr.b))
553
554 gen_r_math_logic(srai, sari_tl,  instr.imm5)
555 gen_r_math_logic(srli, shri_tl,  instr.imm5)
556 gen_r_math_logic(slli, shli_tl,  instr.imm5)
557 gen_r_math_logic(roli, rotli_tl, instr.imm5)
558
559 #define gen_r_mul(fname, insn)                                         \
560 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)   \
561 {                                                                      \
562     R_TYPE(instr, (code));                                             \
563     if (likely(instr.c != R_ZERO)) {                                   \
564         TCGv t0 = tcg_temp_new();                                      \
565         tcg_gen_##insn(t0, dc->cpu_R[instr.c],                         \
566                        load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
567         tcg_temp_free(t0);                                             \
568     }                                                                  \
569 }
570
571 gen_r_mul(mulxss, muls2_tl)
572 gen_r_mul(mulxuu, mulu2_tl)
573 gen_r_mul(mulxsu, mulsu2_tl)
574
575 #define gen_r_shift_s(fname, insn)                                         \
576 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
577 {                                                                          \
578     R_TYPE(instr, (code));                                                 \
579     if (likely(instr.c != R_ZERO)) {                                       \
580         TCGv t0 = tcg_temp_new();                                          \
581         tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31);                  \
582         tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
583         tcg_temp_free(t0);                                                 \
584     }                                                                      \
585 }
586
587 gen_r_shift_s(sra, sar_tl)
588 gen_r_shift_s(srl, shr_tl)
589 gen_r_shift_s(sll, shl_tl)
590 gen_r_shift_s(rol, rotl_tl)
591 gen_r_shift_s(ror, rotr_tl)
592
593 static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
594 {
595     R_TYPE(instr, (code));
596
597     /* Stores into R_ZERO are ignored */
598     if (unlikely(instr.c == R_ZERO)) {
599         return;
600     }
601
602     TCGv t0 = tcg_temp_new();
603     TCGv t1 = tcg_temp_new();
604     TCGv t2 = tcg_temp_new();
605     TCGv t3 = tcg_temp_new();
606
607     tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a));
608     tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b));
609     tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
610     tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
611     tcg_gen_and_tl(t2, t2, t3);
612     tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
613     tcg_gen_or_tl(t2, t2, t3);
614     tcg_gen_movi_tl(t3, 0);
615     tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
616     tcg_gen_div_tl(dc->cpu_R[instr.c], t0, t1);
617     tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
618
619     tcg_temp_free(t3);
620     tcg_temp_free(t2);
621     tcg_temp_free(t1);
622     tcg_temp_free(t0);
623 }
624
625 static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
626 {
627     R_TYPE(instr, (code));
628
629     /* Stores into R_ZERO are ignored */
630     if (unlikely(instr.c == R_ZERO)) {
631         return;
632     }
633
634     TCGv t0 = tcg_temp_new();
635     TCGv t1 = tcg_temp_new();
636     TCGv t2 = tcg_const_tl(0);
637     TCGv t3 = tcg_const_tl(1);
638
639     tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
640     tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
641     tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
642     tcg_gen_divu_tl(dc->cpu_R[instr.c], t0, t1);
643     tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
644
645     tcg_temp_free(t3);
646     tcg_temp_free(t2);
647     tcg_temp_free(t1);
648     tcg_temp_free(t0);
649 }
650
651 static const Nios2Instruction r_type_instructions[] = {
652     INSTRUCTION_ILLEGAL(),
653     INSTRUCTION(eret),                                /* eret */
654     INSTRUCTION(roli),                                /* roli */
655     INSTRUCTION(rol),                                 /* rol */
656     INSTRUCTION_NOP(),                                /* flushp */
657     INSTRUCTION(ret),                                 /* ret */
658     INSTRUCTION(nor),                                 /* nor */
659     INSTRUCTION(mulxuu),                              /* mulxuu */
660     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),          /* cmpge */
661     INSTRUCTION(bret),                                /* bret */
662     INSTRUCTION_ILLEGAL(),
663     INSTRUCTION(ror),                                 /* ror */
664     INSTRUCTION_NOP(),                                /* flushi */
665     INSTRUCTION(jmp),                                 /* jmp */
666     INSTRUCTION(and),                                 /* and */
667     INSTRUCTION_ILLEGAL(),
668     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),          /* cmplt */
669     INSTRUCTION_ILLEGAL(),
670     INSTRUCTION(slli),                                /* slli */
671     INSTRUCTION(sll),                                 /* sll */
672     INSTRUCTION_UNIMPLEMENTED(),                      /* wrprs */
673     INSTRUCTION_ILLEGAL(),
674     INSTRUCTION(or),                                  /* or */
675     INSTRUCTION(mulxsu),                              /* mulxsu */
676     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),          /* cmpne */
677     INSTRUCTION_ILLEGAL(),
678     INSTRUCTION(srli),                                /* srli */
679     INSTRUCTION(srl),                                 /* srl */
680     INSTRUCTION(nextpc),                              /* nextpc */
681     INSTRUCTION(callr),                               /* callr */
682     INSTRUCTION(xor),                                 /* xor */
683     INSTRUCTION(mulxss),                              /* mulxss */
684     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),          /* cmpeq */
685     INSTRUCTION_ILLEGAL(),
686     INSTRUCTION_ILLEGAL(),
687     INSTRUCTION_ILLEGAL(),
688     INSTRUCTION(divu),                                /* divu */
689     INSTRUCTION(divs),                                /* div */
690     INSTRUCTION(rdctl),                               /* rdctl */
691     INSTRUCTION(mul),                                 /* mul */
692     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),         /* cmpgeu */
693     INSTRUCTION_NOP(),                                /* initi */
694     INSTRUCTION_ILLEGAL(),
695     INSTRUCTION_ILLEGAL(),
696     INSTRUCTION_ILLEGAL(),
697     INSTRUCTION_FLG(gen_excp, EXCP_TRAP),             /* trap */
698     INSTRUCTION(wrctl),                               /* wrctl */
699     INSTRUCTION_ILLEGAL(),
700     INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),         /* cmpltu */
701     INSTRUCTION(add),                                 /* add */
702     INSTRUCTION_ILLEGAL(),
703     INSTRUCTION_ILLEGAL(),
704     INSTRUCTION_FLG(gen_excp, EXCP_BREAK),            /* break */
705     INSTRUCTION_ILLEGAL(),
706     INSTRUCTION(nop),                                 /* nop */
707     INSTRUCTION_ILLEGAL(),
708     INSTRUCTION_ILLEGAL(),
709     INSTRUCTION(sub),                                 /* sub */
710     INSTRUCTION(srai),                                /* srai */
711     INSTRUCTION(sra),                                 /* sra */
712     INSTRUCTION_ILLEGAL(),
713     INSTRUCTION_ILLEGAL(),
714     INSTRUCTION_ILLEGAL(),
715     INSTRUCTION_ILLEGAL(),
716 };
717
718 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
719 {
720     uint8_t opx;
721     const Nios2Instruction *instr;
722
723     opx = get_opxcode(code);
724     if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
725         goto illegal_op;
726     }
727
728     instr = &r_type_instructions[opx];
729     instr->handler(dc, code, instr->flags);
730
731     return;
732
733 illegal_op:
734     t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
735 }
736
737 static void handle_instruction(DisasContext *dc, CPUNios2State *env)
738 {
739     uint32_t code;
740     uint8_t op;
741     const Nios2Instruction *instr;
742 #if defined(CONFIG_USER_ONLY)
743     /* FIXME: Is this needed ? */
744     if (dc->pc >= 0x1000 && dc->pc < 0x2000) {
745         env->regs[R_PC] = dc->pc;
746         t_gen_helper_raise_exception(dc, 0xaa);
747         return;
748     }
749 #endif
750     code = cpu_ldl_code(env, dc->pc);
751     op = get_opcode(code);
752
753     if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
754         goto illegal_op;
755     }
756
757     TCGV_UNUSED_I32(dc->zero);
758
759     instr = &i_type_instructions[op];
760     instr->handler(dc, code, instr->flags);
761
762     if (!TCGV_IS_UNUSED_I32(dc->zero)) {
763         tcg_temp_free(dc->zero);
764     }
765
766     return;
767
768 illegal_op:
769     t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
770 }
771
772 static const char * const regnames[] = {
773     "zero",       "at",         "r2",         "r3",
774     "r4",         "r5",         "r6",         "r7",
775     "r8",         "r9",         "r10",        "r11",
776     "r12",        "r13",        "r14",        "r15",
777     "r16",        "r17",        "r18",        "r19",
778     "r20",        "r21",        "r22",        "r23",
779     "et",         "bt",         "gp",         "sp",
780     "fp",         "ea",         "ba",         "ra",
781     "status",     "estatus",    "bstatus",    "ienable",
782     "ipending",   "cpuid",      "reserved0",  "exception",
783     "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
784     "badaddr",    "config",     "mpubase",    "mpuacc",
785     "reserved2",  "reserved3",  "reserved4",  "reserved5",
786     "reserved6",  "reserved7",  "reserved8",  "reserved9",
787     "reserved10", "reserved11", "reserved12", "reserved13",
788     "reserved14", "reserved15", "reserved16", "reserved17",
789     "rpc"
790 };
791
792 static TCGv cpu_R[NUM_CORE_REGS];
793
794 #include "exec/gen-icount.h"
795
796 static void gen_exception(DisasContext *dc, uint32_t excp)
797 {
798     TCGv_i32 tmp = tcg_const_i32(excp);
799
800     tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
801     gen_helper_raise_exception(cpu_env, tmp);
802     tcg_temp_free_i32(tmp);
803     dc->is_jmp = DISAS_UPDATE;
804 }
805
806 /* generate intermediate code for basic block 'tb'.  */
807 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
808 {
809     CPUNios2State *env = cs->env_ptr;
810     DisasContext dc1, *dc = &dc1;
811     int num_insns;
812     int max_insns;
813
814     /* Initialize DC */
815     dc->cpu_env = cpu_env;
816     dc->cpu_R   = cpu_R;
817     dc->is_jmp  = DISAS_NEXT;
818     dc->pc      = tb->pc;
819     dc->tb      = tb;
820     dc->mem_idx = cpu_mmu_index(env, false);
821     dc->singlestep_enabled = cs->singlestep_enabled;
822
823     /* Set up instruction counts */
824     num_insns = 0;
825     if (cs->singlestep_enabled || singlestep) {
826         max_insns = 1;
827     } else {
828         int page_insns = (TARGET_PAGE_SIZE - (tb->pc & TARGET_PAGE_MASK)) / 4;
829         max_insns = tb_cflags(tb) & CF_COUNT_MASK;
830         if (max_insns == 0) {
831             max_insns = CF_COUNT_MASK;
832         }
833         if (max_insns > page_insns) {
834             max_insns = page_insns;
835         }
836         if (max_insns > TCG_MAX_INSNS) {
837             max_insns = TCG_MAX_INSNS;
838         }
839     }
840
841     gen_tb_start(tb);
842     do {
843         tcg_gen_insn_start(dc->pc);
844         num_insns++;
845
846         if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
847             gen_exception(dc, EXCP_DEBUG);
848             /* The address covered by the breakpoint must be included in
849                [tb->pc, tb->pc + tb->size) in order to for it to be
850                properly cleared -- thus we increment the PC here so that
851                the logic setting tb->size below does the right thing.  */
852             dc->pc += 4;
853             break;
854         }
855
856         if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
857             gen_io_start();
858         }
859
860         /* Decode an instruction */
861         handle_instruction(dc, env);
862
863         dc->pc += 4;
864
865         /* Translation stops when a conditional branch is encountered.
866          * Otherwise the subsequent code could get translated several times.
867          * Also stop translation when a page boundary is reached.  This
868          * ensures prefetch aborts occur at the right place.  */
869     } while (!dc->is_jmp &&
870              !tcg_op_buf_full() &&
871              num_insns < max_insns);
872
873     if (tb_cflags(tb) & CF_LAST_IO) {
874         gen_io_end();
875     }
876
877     /* Indicate where the next block should start */
878     switch (dc->is_jmp) {
879     case DISAS_NEXT:
880         /* Save the current PC back into the CPU register */
881         tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
882         tcg_gen_exit_tb(0);
883         break;
884
885     default:
886     case DISAS_JUMP:
887     case DISAS_UPDATE:
888         /* The jump will already have updated the PC register */
889         tcg_gen_exit_tb(0);
890         break;
891
892     case DISAS_TB_JUMP:
893         /* nothing more to generate */
894         break;
895     }
896
897     /* End off the block */
898     gen_tb_end(tb, num_insns);
899
900     /* Mark instruction starts for the final generated instruction */
901     tb->size = dc->pc - tb->pc;
902     tb->icount = num_insns;
903
904 #ifdef DEBUG_DISAS
905     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
906         && qemu_log_in_addr_range(tb->pc)) {
907         qemu_log_lock();
908         qemu_log("IN: %s\n", lookup_symbol(tb->pc));
909         log_target_disas(cs, tb->pc, dc->pc - tb->pc);
910         qemu_log("\n");
911         qemu_log_unlock();
912     }
913 #endif
914 }
915
916 void nios2_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
917                           int flags)
918 {
919     Nios2CPU *cpu = NIOS2_CPU(cs);
920     CPUNios2State *env = &cpu->env;
921     int i;
922
923     if (!env || !f) {
924         return;
925     }
926
927     cpu_fprintf(f, "IN: PC=%x %s\n",
928                 env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
929
930     for (i = 0; i < NUM_CORE_REGS; i++) {
931         cpu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
932         if ((i + 1) % 4 == 0) {
933             cpu_fprintf(f, "\n");
934         }
935     }
936 #if !defined(CONFIG_USER_ONLY)
937     cpu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
938                 env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
939                 (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
940                 env->mmu.tlbacc_wr);
941 #endif
942     cpu_fprintf(f, "\n\n");
943 }
944
945 void nios2_tcg_init(void)
946 {
947     int i;
948
949     for (i = 0; i < NUM_CORE_REGS; i++) {
950         cpu_R[i] = tcg_global_mem_new(cpu_env,
951                                       offsetof(CPUNios2State, regs[i]),
952                                       regnames[i]);
953     }
954 }
955
956 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
957                           target_ulong *data)
958 {
959     env->regs[R_PC] = data[0];
960 }
This page took 0.07957 seconds and 4 git commands to generate.