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