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