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