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