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