]> git.proxmox.com Git - mirror_qemu.git/blob - target/nios2/translate.c
Merge tag 'seabios-hppa-v7-pull-request' of https://github.com/hdeller/qemu-hppa...
[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 "semihosting/semihost.h"
36
37 #define HELPER_H "helper.h"
38 #include "exec/helper-info.c.inc"
39 #undef HELPER_H
40
41
42 /* is_jmp field values */
43 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
44
45 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
46 #define INSTRUCTION(func) \
47 INSTRUCTION_FLG(func, 0)
48 #define INSTRUCTION_NOP() \
49 INSTRUCTION_FLG(nop, 0)
50 #define INSTRUCTION_UNIMPLEMENTED() \
51 INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
52 #define INSTRUCTION_ILLEGAL() \
53 INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
54
55 /* Special R-Type instruction opcode */
56 #define INSN_R_TYPE 0x3A
57
58 /* I-Type instruction parsing */
59 typedef struct {
60 uint8_t op;
61 union {
62 uint16_t u;
63 int16_t s;
64 } imm16;
65 uint8_t b;
66 uint8_t a;
67 } InstrIType;
68
69 #define I_TYPE(instr, code) \
70 InstrIType (instr) = { \
71 .op = extract32((code), 0, 6), \
72 .imm16.u = extract32((code), 6, 16), \
73 .b = extract32((code), 22, 5), \
74 .a = extract32((code), 27, 5), \
75 }
76
77 typedef target_ulong ImmFromIType(const InstrIType *);
78
79 static target_ulong imm_unsigned(const InstrIType *i)
80 {
81 return i->imm16.u;
82 }
83
84 static target_ulong imm_signed(const InstrIType *i)
85 {
86 return i->imm16.s;
87 }
88
89 static target_ulong imm_shifted(const InstrIType *i)
90 {
91 return i->imm16.u << 16;
92 }
93
94 /* R-Type instruction parsing */
95 typedef struct {
96 uint8_t op;
97 uint8_t imm5;
98 uint8_t opx;
99 uint8_t c;
100 uint8_t b;
101 uint8_t a;
102 } InstrRType;
103
104 #define R_TYPE(instr, code) \
105 InstrRType (instr) = { \
106 .op = extract32((code), 0, 6), \
107 .imm5 = extract32((code), 6, 5), \
108 .opx = extract32((code), 11, 6), \
109 .c = extract32((code), 17, 5), \
110 .b = extract32((code), 22, 5), \
111 .a = extract32((code), 27, 5), \
112 }
113
114 /* J-Type instruction parsing */
115 typedef struct {
116 uint8_t op;
117 uint32_t imm26;
118 } InstrJType;
119
120 #define J_TYPE(instr, code) \
121 InstrJType (instr) = { \
122 .op = extract32((code), 0, 6), \
123 .imm26 = extract32((code), 6, 26), \
124 }
125
126 typedef void GenFn2i(TCGv, TCGv, target_long);
127 typedef void GenFn3(TCGv, TCGv, TCGv);
128 typedef void GenFn4(TCGv, TCGv, TCGv, TCGv);
129
130 typedef struct DisasContext {
131 DisasContextBase base;
132 target_ulong pc;
133 int mem_idx;
134 uint32_t tb_flags;
135 TCGv sink;
136 const ControlRegState *cr_state;
137 bool eic_present;
138 } DisasContext;
139
140 static TCGv cpu_R[NUM_GP_REGS];
141 static TCGv cpu_pc;
142 #ifndef CONFIG_USER_ONLY
143 static TCGv cpu_crs_R[NUM_GP_REGS];
144 #endif
145
146 typedef struct Nios2Instruction {
147 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
148 uint32_t flags;
149 } Nios2Instruction;
150
151 static uint8_t get_opcode(uint32_t code)
152 {
153 I_TYPE(instr, code);
154 return instr.op;
155 }
156
157 static uint8_t get_opxcode(uint32_t code)
158 {
159 R_TYPE(instr, code);
160 return instr.opx;
161 }
162
163 static TCGv load_gpr(DisasContext *dc, unsigned reg)
164 {
165 assert(reg < NUM_GP_REGS);
166
167 /*
168 * With shadow register sets, register r0 does not necessarily contain 0,
169 * but it is overwhelmingly likely that it does -- software is supposed
170 * to have set r0 to 0 in every shadow register set before use.
171 */
172 if (unlikely(reg == R_ZERO) && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
173 return tcg_constant_tl(0);
174 }
175 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
176 return cpu_R[reg];
177 }
178 #ifdef CONFIG_USER_ONLY
179 g_assert_not_reached();
180 #else
181 return cpu_crs_R[reg];
182 #endif
183 }
184
185 static TCGv dest_gpr(DisasContext *dc, unsigned reg)
186 {
187 assert(reg < NUM_GP_REGS);
188
189 /*
190 * The spec for shadow register sets isn't clear, but we assume that
191 * writes to r0 are discarded regardless of CRS.
192 */
193 if (unlikely(reg == R_ZERO)) {
194 if (dc->sink == NULL) {
195 dc->sink = tcg_temp_new();
196 }
197 return dc->sink;
198 }
199 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
200 return cpu_R[reg];
201 }
202 #ifdef CONFIG_USER_ONLY
203 g_assert_not_reached();
204 #else
205 return cpu_crs_R[reg];
206 #endif
207 }
208
209 static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
210 {
211 /* Note that PC is advanced for all hardware exceptions. */
212 tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
213 gen_helper_raise_exception(cpu_env, tcg_constant_i32(index));
214 dc->base.is_jmp = DISAS_NORETURN;
215 }
216
217 static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
218 {
219 const TranslationBlock *tb = dc->base.tb;
220
221 if (translator_use_goto_tb(&dc->base, dest)) {
222 tcg_gen_goto_tb(n);
223 tcg_gen_movi_tl(cpu_pc, dest);
224 tcg_gen_exit_tb(tb, n);
225 } else {
226 tcg_gen_movi_tl(cpu_pc, dest);
227 tcg_gen_lookup_and_goto_ptr();
228 }
229 dc->base.is_jmp = DISAS_NORETURN;
230 }
231
232 static void gen_jumpr(DisasContext *dc, int regno, bool is_call)
233 {
234 TCGLabel *l = gen_new_label();
235 TCGv test = tcg_temp_new();
236 TCGv dest = load_gpr(dc, regno);
237
238 tcg_gen_andi_tl(test, dest, 3);
239 tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l);
240
241 tcg_gen_mov_tl(cpu_pc, dest);
242 if (is_call) {
243 tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
244 }
245 tcg_gen_lookup_and_goto_ptr();
246
247 gen_set_label(l);
248 tcg_gen_st_tl(dest, cpu_env, offsetof(CPUNios2State, ctrl[CR_BADADDR]));
249 t_gen_helper_raise_exception(dc, EXCP_UNALIGND);
250
251 dc->base.is_jmp = DISAS_NORETURN;
252 }
253
254 static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
255 {
256 t_gen_helper_raise_exception(dc, flags);
257 }
258
259 static bool gen_check_supervisor(DisasContext *dc)
260 {
261 if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) {
262 /* CPU in user mode, privileged instruction called, stop. */
263 t_gen_helper_raise_exception(dc, EXCP_SUPERI);
264 return false;
265 }
266 return true;
267 }
268
269 /*
270 * Used as a placeholder for all instructions which do not have
271 * an effect on the simulator (e.g. flush, sync)
272 */
273 static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
274 {
275 /* Nothing to do here */
276 }
277
278 /*
279 * J-Type instructions
280 */
281 static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
282 {
283 J_TYPE(instr, code);
284 gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
285 }
286
287 static void call(DisasContext *dc, uint32_t code, uint32_t flags)
288 {
289 tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
290 jmpi(dc, code, flags);
291 }
292
293 /*
294 * I-Type instructions
295 */
296 /* Load instructions */
297 static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
298 {
299 I_TYPE(instr, code);
300
301 TCGv addr = tcg_temp_new();
302 TCGv data = dest_gpr(dc, instr.b);
303
304 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
305 #ifdef CONFIG_USER_ONLY
306 flags |= MO_UNALN;
307 #else
308 flags |= MO_ALIGN;
309 #endif
310 tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
311 }
312
313 /* Store instructions */
314 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
315 {
316 I_TYPE(instr, code);
317 TCGv val = load_gpr(dc, instr.b);
318
319 TCGv addr = tcg_temp_new();
320 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
321 #ifdef CONFIG_USER_ONLY
322 flags |= MO_UNALN;
323 #else
324 flags |= MO_ALIGN;
325 #endif
326 tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
327 }
328
329 /* Branch instructions */
330 static void br(DisasContext *dc, uint32_t code, uint32_t flags)
331 {
332 I_TYPE(instr, code);
333
334 gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4));
335 }
336
337 static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
338 {
339 I_TYPE(instr, code);
340
341 TCGLabel *l1 = gen_new_label();
342 tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1);
343 gen_goto_tb(dc, 0, dc->base.pc_next);
344 gen_set_label(l1);
345 gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
346 }
347
348 /* Comparison instructions */
349 static void do_i_cmpxx(DisasContext *dc, uint32_t insn,
350 TCGCond cond, ImmFromIType *imm)
351 {
352 I_TYPE(instr, insn);
353 tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b),
354 load_gpr(dc, instr.a), imm(&instr));
355 }
356
357 #define gen_i_cmpxx(fname, imm) \
358 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
359 { do_i_cmpxx(dc, code, flags, imm); }
360
361 gen_i_cmpxx(gen_cmpxxsi, imm_signed)
362 gen_i_cmpxx(gen_cmpxxui, imm_unsigned)
363
364 /* Math/logic instructions */
365 static void do_i_math_logic(DisasContext *dc, uint32_t insn,
366 GenFn2i *fn, ImmFromIType *imm,
367 bool x_op_0_eq_x)
368 {
369 I_TYPE(instr, insn);
370 target_ulong val;
371
372 if (unlikely(instr.b == R_ZERO)) {
373 /* Store to R_ZERO is ignored -- this catches the canonical NOP. */
374 return;
375 }
376
377 val = imm(&instr);
378
379 if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
380 /* This catches the canonical expansions of movi and movhi. */
381 tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0);
382 } else {
383 fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val);
384 }
385 }
386
387 #define gen_i_math_logic(fname, insn, x_op_0, imm) \
388 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
389 { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); }
390
391 gen_i_math_logic(addi, addi, 1, imm_signed)
392 gen_i_math_logic(muli, muli, 0, imm_signed)
393
394 gen_i_math_logic(andi, andi, 0, imm_unsigned)
395 gen_i_math_logic(ori, ori, 1, imm_unsigned)
396 gen_i_math_logic(xori, xori, 1, imm_unsigned)
397
398 gen_i_math_logic(andhi, andi, 0, imm_shifted)
399 gen_i_math_logic(orhi , ori, 1, imm_shifted)
400 gen_i_math_logic(xorhi, xori, 1, imm_shifted)
401
402 /* rB <- prs.rA + sigma(IMM16) */
403 static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags)
404 {
405 if (!dc->eic_present) {
406 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
407 return;
408 }
409 if (!gen_check_supervisor(dc)) {
410 return;
411 }
412
413 #ifdef CONFIG_USER_ONLY
414 g_assert_not_reached();
415 #else
416 I_TYPE(instr, code);
417 TCGv dest = dest_gpr(dc, instr.b);
418 gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a));
419 tcg_gen_addi_tl(dest, dest, instr.imm16.s);
420 #endif
421 }
422
423 /* Prototype only, defined below */
424 static void handle_r_type_instr(DisasContext *dc, uint32_t code,
425 uint32_t flags);
426
427 static const Nios2Instruction i_type_instructions[] = {
428 INSTRUCTION(call), /* call */
429 INSTRUCTION(jmpi), /* jmpi */
430 INSTRUCTION_ILLEGAL(),
431 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */
432 INSTRUCTION(addi), /* addi */
433 INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */
434 INSTRUCTION(br), /* br */
435 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */
436 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */
437 INSTRUCTION_ILLEGAL(),
438 INSTRUCTION_ILLEGAL(),
439 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhu */
440 INSTRUCTION(andi), /* andi */
441 INSTRUCTION_FLG(gen_stx, MO_UW), /* sth */
442 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */
443 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldh */
444 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */
445 INSTRUCTION_ILLEGAL(),
446 INSTRUCTION_ILLEGAL(),
447 INSTRUCTION_NOP(), /* initda */
448 INSTRUCTION(ori), /* ori */
449 INSTRUCTION_FLG(gen_stx, MO_UL), /* stw */
450 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */
451 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldw */
452 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */
453 INSTRUCTION_ILLEGAL(),
454 INSTRUCTION_ILLEGAL(),
455 INSTRUCTION_NOP(), /* flushda */
456 INSTRUCTION(xori), /* xori */
457 INSTRUCTION_ILLEGAL(),
458 INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */
459 INSTRUCTION_ILLEGAL(),
460 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */
461 INSTRUCTION_ILLEGAL(),
462 INSTRUCTION_ILLEGAL(),
463 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */
464 INSTRUCTION(muli), /* muli */
465 INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */
466 INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */
467 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */
468 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */
469 INSTRUCTION_ILLEGAL(),
470 INSTRUCTION_ILLEGAL(),
471 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhuio */
472 INSTRUCTION(andhi), /* andhi */
473 INSTRUCTION_FLG(gen_stx, MO_UW), /* sthio */
474 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */
475 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldhio */
476 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */
477 INSTRUCTION_ILLEGAL(),
478 INSTRUCTION_UNIMPLEMENTED(), /* custom */
479 INSTRUCTION_NOP(), /* initd */
480 INSTRUCTION(orhi), /* orhi */
481 INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */
482 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */
483 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */
484 INSTRUCTION(rdprs), /* rdprs */
485 INSTRUCTION_ILLEGAL(),
486 INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */
487 INSTRUCTION_NOP(), /* flushd */
488 INSTRUCTION(xorhi), /* xorhi */
489 INSTRUCTION_ILLEGAL(),
490 INSTRUCTION_ILLEGAL(),
491 INSTRUCTION_ILLEGAL(),
492 };
493
494 /*
495 * R-Type instructions
496 */
497 /*
498 * status <- estatus
499 * PC <- ea
500 */
501 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
502 {
503 if (!gen_check_supervisor(dc)) {
504 return;
505 }
506
507 #ifdef CONFIG_USER_ONLY
508 g_assert_not_reached();
509 #else
510 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
511 TCGv tmp = tcg_temp_new();
512 tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS]));
513 gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_EA));
514 } else {
515 gen_helper_eret(cpu_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA));
516 }
517 dc->base.is_jmp = DISAS_NORETURN;
518 #endif
519 }
520
521 /* PC <- ra */
522 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
523 {
524 gen_jumpr(dc, R_RA, false);
525 }
526
527 /*
528 * status <- bstatus
529 * PC <- ba
530 */
531 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
532 {
533 if (!gen_check_supervisor(dc)) {
534 return;
535 }
536
537 #ifdef CONFIG_USER_ONLY
538 g_assert_not_reached();
539 #else
540 TCGv tmp = tcg_temp_new();
541 tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS]));
542 gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_BA));
543
544 dc->base.is_jmp = DISAS_NORETURN;
545 #endif
546 }
547
548 /* PC <- rA */
549 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
550 {
551 R_TYPE(instr, code);
552
553 gen_jumpr(dc, instr.a, false);
554 }
555
556 /* rC <- PC + 4 */
557 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
558 {
559 R_TYPE(instr, code);
560
561 tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next);
562 }
563
564 /*
565 * ra <- PC + 4
566 * PC <- rA
567 */
568 static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
569 {
570 R_TYPE(instr, code);
571
572 gen_jumpr(dc, instr.a, true);
573 }
574
575 /* rC <- ctlN */
576 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
577 {
578 if (!gen_check_supervisor(dc)) {
579 return;
580 }
581
582 #ifdef CONFIG_USER_ONLY
583 g_assert_not_reached();
584 #else
585 R_TYPE(instr, code);
586 TCGv t1, t2, dest = dest_gpr(dc, instr.c);
587
588 /* Reserved registers read as zero. */
589 if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
590 tcg_gen_movi_tl(dest, 0);
591 return;
592 }
593
594 switch (instr.imm5) {
595 case CR_IPENDING:
596 /*
597 * The value of the ipending register is synthetic.
598 * In hw, this is the AND of a set of hardware irq lines
599 * with the ienable register. In qemu, we re-use the space
600 * of CR_IPENDING to store the set of irq lines, and so we
601 * must perform the AND here, and anywhere else we need the
602 * guest value of ipending.
603 */
604 t1 = tcg_temp_new();
605 t2 = tcg_temp_new();
606 tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ctrl[CR_IPENDING]));
607 tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ctrl[CR_IENABLE]));
608 tcg_gen_and_tl(dest, t1, t2);
609 break;
610 default:
611 tcg_gen_ld_tl(dest, cpu_env,
612 offsetof(CPUNios2State, ctrl[instr.imm5]));
613 break;
614 }
615 #endif
616 }
617
618 /* ctlN <- rA */
619 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
620 {
621 if (!gen_check_supervisor(dc)) {
622 return;
623 }
624
625 #ifdef CONFIG_USER_ONLY
626 g_assert_not_reached();
627 #else
628 R_TYPE(instr, code);
629 TCGv v = load_gpr(dc, instr.a);
630 uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]);
631 uint32_t wr = dc->cr_state[instr.imm5].writable;
632 uint32_t ro = dc->cr_state[instr.imm5].readonly;
633
634 /* Skip reserved or readonly registers. */
635 if (wr == 0) {
636 return;
637 }
638
639 switch (instr.imm5) {
640 case CR_PTEADDR:
641 gen_helper_mmu_write_pteaddr(cpu_env, v);
642 break;
643 case CR_TLBACC:
644 gen_helper_mmu_write_tlbacc(cpu_env, v);
645 break;
646 case CR_TLBMISC:
647 gen_helper_mmu_write_tlbmisc(cpu_env, v);
648 break;
649 case CR_STATUS:
650 case CR_IENABLE:
651 /* If interrupts were enabled using WRCTL, trigger them. */
652 dc->base.is_jmp = DISAS_UPDATE;
653 /* fall through */
654 default:
655 if (wr == -1) {
656 /* The register is entirely writable. */
657 tcg_gen_st_tl(v, cpu_env, ofs);
658 } else {
659 /*
660 * The register is partially read-only or reserved:
661 * merge the value.
662 */
663 TCGv n = tcg_temp_new();
664
665 tcg_gen_andi_tl(n, v, wr);
666
667 if (ro != 0) {
668 TCGv o = tcg_temp_new();
669 tcg_gen_ld_tl(o, cpu_env, ofs);
670 tcg_gen_andi_tl(o, o, ro);
671 tcg_gen_or_tl(n, n, o);
672 }
673
674 tcg_gen_st_tl(n, cpu_env, ofs);
675 }
676 break;
677 }
678 #endif
679 }
680
681 /* prs.rC <- rA */
682 static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags)
683 {
684 if (!dc->eic_present) {
685 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
686 return;
687 }
688 if (!gen_check_supervisor(dc)) {
689 return;
690 }
691
692 #ifdef CONFIG_USER_ONLY
693 g_assert_not_reached();
694 #else
695 R_TYPE(instr, code);
696 gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c),
697 load_gpr(dc, instr.a));
698 /*
699 * The expected write to PRS[r0] is 0, from CRS[r0].
700 * If not, and CRS == PRS (which we cannot tell from here),
701 * we may now have a non-zero value in our current r0.
702 * By ending the TB, we re-evaluate tb_flags and find out.
703 */
704 if (instr.c == 0
705 && (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) {
706 dc->base.is_jmp = DISAS_UPDATE;
707 }
708 #endif
709 }
710
711 /* Comparison instructions */
712 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
713 {
714 R_TYPE(instr, code);
715 tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c),
716 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
717 }
718
719 /* Math/logic instructions */
720 static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn)
721 {
722 R_TYPE(instr, insn);
723 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5);
724 }
725
726 static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn)
727 {
728 R_TYPE(instr, insn);
729 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b));
730 }
731
732 #define gen_ri_math_logic(fname, insn) \
733 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
734 { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); }
735
736 #define gen_rr_math_logic(fname, insn) \
737 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
738 { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); }
739
740 gen_rr_math_logic(add, add)
741 gen_rr_math_logic(sub, sub)
742 gen_rr_math_logic(mul, mul)
743
744 gen_rr_math_logic(and, and)
745 gen_rr_math_logic(or, or)
746 gen_rr_math_logic(xor, xor)
747 gen_rr_math_logic(nor, nor)
748
749 gen_ri_math_logic(srai, sari)
750 gen_ri_math_logic(srli, shri)
751 gen_ri_math_logic(slli, shli)
752 gen_ri_math_logic(roli, rotli)
753
754 static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn)
755 {
756 R_TYPE(instr, insn);
757 TCGv discard = tcg_temp_new();
758
759 fn(discard, dest_gpr(dc, instr.c),
760 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
761 }
762
763 #define gen_rr_mul_high(fname, insn) \
764 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
765 { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); }
766
767 gen_rr_mul_high(mulxss, muls2)
768 gen_rr_mul_high(mulxuu, mulu2)
769 gen_rr_mul_high(mulxsu, mulsu2)
770
771 static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn)
772 {
773 R_TYPE(instr, insn);
774 TCGv sh = tcg_temp_new();
775
776 tcg_gen_andi_tl(sh, load_gpr(dc, instr.b), 31);
777 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), sh);
778 }
779
780 #define gen_rr_shift(fname, insn) \
781 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
782 { do_rr_shift(dc, code, tcg_gen_##insn##_tl); }
783
784 gen_rr_shift(sra, sar)
785 gen_rr_shift(srl, shr)
786 gen_rr_shift(sll, shl)
787 gen_rr_shift(rol, rotl)
788 gen_rr_shift(ror, rotr)
789
790 static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
791 {
792 R_TYPE(instr, (code));
793 gen_helper_divs(dest_gpr(dc, instr.c), cpu_env,
794 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
795 }
796
797 static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
798 {
799 R_TYPE(instr, (code));
800 gen_helper_divu(dest_gpr(dc, instr.c), cpu_env,
801 load_gpr(dc, instr.a), load_gpr(dc, instr.b));
802 }
803
804 static void trap(DisasContext *dc, uint32_t code, uint32_t flags)
805 {
806 #ifdef CONFIG_USER_ONLY
807 /*
808 * The imm5 field is not stored anywhere on real hw; the kernel
809 * has to load the insn and extract the field. But we can make
810 * things easier for cpu_loop if we pop this into env->error_code.
811 */
812 R_TYPE(instr, code);
813 tcg_gen_st_i32(tcg_constant_i32(instr.imm5), cpu_env,
814 offsetof(CPUNios2State, error_code));
815 #endif
816 t_gen_helper_raise_exception(dc, EXCP_TRAP);
817 }
818
819 static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags)
820 {
821 #ifndef CONFIG_USER_ONLY
822 /* The semihosting instruction is "break 1". */
823 bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U);
824 R_TYPE(instr, code);
825 if (semihosting_enabled(is_user) && instr.imm5 == 1) {
826 t_gen_helper_raise_exception(dc, EXCP_SEMIHOST);
827 return;
828 }
829 #endif
830
831 t_gen_helper_raise_exception(dc, EXCP_BREAK);
832 }
833
834 static const Nios2Instruction r_type_instructions[] = {
835 INSTRUCTION_ILLEGAL(),
836 INSTRUCTION(eret), /* eret */
837 INSTRUCTION(roli), /* roli */
838 INSTRUCTION(rol), /* rol */
839 INSTRUCTION_NOP(), /* flushp */
840 INSTRUCTION(ret), /* ret */
841 INSTRUCTION(nor), /* nor */
842 INSTRUCTION(mulxuu), /* mulxuu */
843 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */
844 INSTRUCTION(bret), /* bret */
845 INSTRUCTION_ILLEGAL(),
846 INSTRUCTION(ror), /* ror */
847 INSTRUCTION_NOP(), /* flushi */
848 INSTRUCTION(jmp), /* jmp */
849 INSTRUCTION(and), /* and */
850 INSTRUCTION_ILLEGAL(),
851 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */
852 INSTRUCTION_ILLEGAL(),
853 INSTRUCTION(slli), /* slli */
854 INSTRUCTION(sll), /* sll */
855 INSTRUCTION(wrprs), /* wrprs */
856 INSTRUCTION_ILLEGAL(),
857 INSTRUCTION(or), /* or */
858 INSTRUCTION(mulxsu), /* mulxsu */
859 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */
860 INSTRUCTION_ILLEGAL(),
861 INSTRUCTION(srli), /* srli */
862 INSTRUCTION(srl), /* srl */
863 INSTRUCTION(nextpc), /* nextpc */
864 INSTRUCTION(callr), /* callr */
865 INSTRUCTION(xor), /* xor */
866 INSTRUCTION(mulxss), /* mulxss */
867 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */
868 INSTRUCTION_ILLEGAL(),
869 INSTRUCTION_ILLEGAL(),
870 INSTRUCTION_ILLEGAL(),
871 INSTRUCTION(divu), /* divu */
872 INSTRUCTION(divs), /* div */
873 INSTRUCTION(rdctl), /* rdctl */
874 INSTRUCTION(mul), /* mul */
875 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */
876 INSTRUCTION_NOP(), /* initi */
877 INSTRUCTION_ILLEGAL(),
878 INSTRUCTION_ILLEGAL(),
879 INSTRUCTION_ILLEGAL(),
880 INSTRUCTION(trap), /* trap */
881 INSTRUCTION(wrctl), /* wrctl */
882 INSTRUCTION_ILLEGAL(),
883 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */
884 INSTRUCTION(add), /* add */
885 INSTRUCTION_ILLEGAL(),
886 INSTRUCTION_ILLEGAL(),
887 INSTRUCTION(gen_break), /* break */
888 INSTRUCTION_ILLEGAL(),
889 INSTRUCTION(nop), /* nop */
890 INSTRUCTION_ILLEGAL(),
891 INSTRUCTION_ILLEGAL(),
892 INSTRUCTION(sub), /* sub */
893 INSTRUCTION(srai), /* srai */
894 INSTRUCTION(sra), /* sra */
895 INSTRUCTION_ILLEGAL(),
896 INSTRUCTION_ILLEGAL(),
897 INSTRUCTION_ILLEGAL(),
898 INSTRUCTION_ILLEGAL(),
899 };
900
901 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
902 {
903 uint8_t opx;
904 const Nios2Instruction *instr;
905
906 opx = get_opxcode(code);
907 if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
908 goto illegal_op;
909 }
910
911 instr = &r_type_instructions[opx];
912 instr->handler(dc, code, instr->flags);
913
914 return;
915
916 illegal_op:
917 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
918 }
919
920 static const char * const gr_regnames[NUM_GP_REGS] = {
921 "zero", "at", "r2", "r3",
922 "r4", "r5", "r6", "r7",
923 "r8", "r9", "r10", "r11",
924 "r12", "r13", "r14", "r15",
925 "r16", "r17", "r18", "r19",
926 "r20", "r21", "r22", "r23",
927 "et", "bt", "gp", "sp",
928 "fp", "ea", "ba", "ra",
929 };
930
931 #ifndef CONFIG_USER_ONLY
932 static const char * const cr_regnames[NUM_CR_REGS] = {
933 "status", "estatus", "bstatus", "ienable",
934 "ipending", "cpuid", "res6", "exception",
935 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
936 "badaddr", "config", "mpubase", "mpuacc",
937 "res16", "res17", "res18", "res19",
938 "res20", "res21", "res22", "res23",
939 "res24", "res25", "res26", "res27",
940 "res28", "res29", "res30", "res31",
941 };
942 #endif
943
944 /* generate intermediate code for basic block 'tb'. */
945 static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
946 {
947 DisasContext *dc = container_of(dcbase, DisasContext, base);
948 CPUNios2State *env = cs->env_ptr;
949 Nios2CPU *cpu = env_archcpu(env);
950 int page_insns;
951
952 dc->mem_idx = cpu_mmu_index(env, false);
953 dc->cr_state = cpu->cr_state;
954 dc->tb_flags = dc->base.tb->flags;
955 dc->eic_present = cpu->eic_present;
956
957 /* Bound the number of insns to execute to those left on the page. */
958 page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
959 dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
960 }
961
962 static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
963 {
964 }
965
966 static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
967 {
968 tcg_gen_insn_start(dcbase->pc_next);
969 }
970
971 static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
972 {
973 DisasContext *dc = container_of(dcbase, DisasContext, base);
974 CPUNios2State *env = cs->env_ptr;
975 const Nios2Instruction *instr;
976 uint32_t code, pc;
977 uint8_t op;
978
979 pc = dc->base.pc_next;
980 dc->pc = pc;
981 dc->base.pc_next = pc + 4;
982
983 /* Decode an instruction */
984 code = cpu_ldl_code(env, pc);
985 op = get_opcode(code);
986
987 if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
988 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
989 return;
990 }
991
992 dc->sink = NULL;
993
994 instr = &i_type_instructions[op];
995 instr->handler(dc, code, instr->flags);
996 }
997
998 static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
999 {
1000 DisasContext *dc = container_of(dcbase, DisasContext, base);
1001
1002 /* Indicate where the next block should start */
1003 switch (dc->base.is_jmp) {
1004 case DISAS_TOO_MANY:
1005 gen_goto_tb(dc, 0, dc->base.pc_next);
1006 break;
1007
1008 case DISAS_UPDATE:
1009 /* Save the current PC, and return to the main loop. */
1010 tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
1011 tcg_gen_exit_tb(NULL, 0);
1012 break;
1013
1014 case DISAS_NORETURN:
1015 /* nothing more to generate */
1016 break;
1017
1018 default:
1019 g_assert_not_reached();
1020 }
1021 }
1022
1023 static void nios2_tr_disas_log(const DisasContextBase *dcbase,
1024 CPUState *cpu, FILE *logfile)
1025 {
1026 fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
1027 target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
1028 }
1029
1030 static const TranslatorOps nios2_tr_ops = {
1031 .init_disas_context = nios2_tr_init_disas_context,
1032 .tb_start = nios2_tr_tb_start,
1033 .insn_start = nios2_tr_insn_start,
1034 .translate_insn = nios2_tr_translate_insn,
1035 .tb_stop = nios2_tr_tb_stop,
1036 .disas_log = nios2_tr_disas_log,
1037 };
1038
1039 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
1040 target_ulong pc, void *host_pc)
1041 {
1042 DisasContext dc;
1043 translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base);
1044 }
1045
1046 void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1047 {
1048 Nios2CPU *cpu = NIOS2_CPU(cs);
1049 CPUNios2State *env = &cpu->env;
1050 int i;
1051
1052 qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
1053
1054 for (i = 0; i < NUM_GP_REGS; i++) {
1055 qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]);
1056 if ((i + 1) % 4 == 0) {
1057 qemu_fprintf(f, "\n");
1058 }
1059 }
1060
1061 #if !defined(CONFIG_USER_ONLY)
1062 int j;
1063
1064 for (i = j = 0; i < NUM_CR_REGS; i++) {
1065 if (!nios2_cr_reserved(&cpu->cr_state[i])) {
1066 qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
1067 if (++j % 4 == 0) {
1068 qemu_fprintf(f, "\n");
1069 }
1070 }
1071 }
1072 if (j % 4 != 0) {
1073 qemu_fprintf(f, "\n");
1074 }
1075 if (cpu->mmu_present) {
1076 qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
1077 env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
1078 FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
1079 env->mmu.tlbacc_wr);
1080 }
1081 #endif
1082 qemu_fprintf(f, "\n\n");
1083 }
1084
1085 void nios2_tcg_init(void)
1086 {
1087 #ifndef CONFIG_USER_ONLY
1088 TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env,
1089 offsetof(CPUNios2State, regs), "crs");
1090
1091 for (int i = 0; i < NUM_GP_REGS; i++) {
1092 cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
1093 }
1094
1095 #define offsetof_regs0(N) offsetof(CPUNios2State, shadow_regs[0][N])
1096 #else
1097 #define offsetof_regs0(N) offsetof(CPUNios2State, regs[N])
1098 #endif
1099
1100 for (int i = 0; i < NUM_GP_REGS; i++) {
1101 cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i),
1102 gr_regnames[i]);
1103 }
1104
1105 #undef offsetof_regs0
1106
1107 cpu_pc = tcg_global_mem_new(cpu_env,
1108 offsetof(CPUNios2State, pc), "pc");
1109 }