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