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