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 "semihosting/semihost.h"
36
37#define HELPER_H "helper.h"
38#include "exec/helper-info.c.inc"
39#undef HELPER_H
40
41
42
43#define DISAS_UPDATE DISAS_TARGET_1
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
56#define INSN_R_TYPE 0x3A
57
58
59typedef 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
77typedef target_ulong ImmFromIType(const InstrIType *);
78
79static target_ulong imm_unsigned(const InstrIType *i)
80{
81 return i->imm16.u;
82}
83
84static target_ulong imm_signed(const InstrIType *i)
85{
86 return i->imm16.s;
87}
88
89static target_ulong imm_shifted(const InstrIType *i)
90{
91 return i->imm16.u << 16;
92}
93
94
95typedef 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
115typedef 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
126typedef void GenFn2i(TCGv, TCGv, target_long);
127typedef void GenFn3(TCGv, TCGv, TCGv);
128typedef void GenFn4(TCGv, TCGv, TCGv, TCGv);
129
130typedef 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
140static TCGv cpu_R[NUM_GP_REGS];
141static TCGv cpu_pc;
142#ifndef CONFIG_USER_ONLY
143static TCGv cpu_crs_R[NUM_GP_REGS];
144#endif
145
146typedef struct Nios2Instruction {
147 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
148 uint32_t flags;
149} Nios2Instruction;
150
151static uint8_t get_opcode(uint32_t code)
152{
153 I_TYPE(instr, code);
154 return instr.op;
155}
156
157static uint8_t get_opxcode(uint32_t code)
158{
159 R_TYPE(instr, code);
160 return instr.opx;
161}
162
163static TCGv load_gpr(DisasContext *dc, unsigned reg)
164{
165 assert(reg < NUM_GP_REGS);
166
167
168
169
170
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
185static TCGv dest_gpr(DisasContext *dc, unsigned reg)
186{
187 assert(reg < NUM_GP_REGS);
188
189
190
191
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
209static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
210{
211
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
217static 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
232static 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
254static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
255{
256 t_gen_helper_raise_exception(dc, flags);
257}
258
259static bool gen_check_supervisor(DisasContext *dc)
260{
261 if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) {
262
263 t_gen_helper_raise_exception(dc, EXCP_SUPERI);
264 return false;
265 }
266 return true;
267}
268
269
270
271
272
273static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
274{
275
276}
277
278
279
280
281static 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
287static 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
295
296
297static 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
314static 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
330static 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
337static 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
349static 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
361gen_i_cmpxx(gen_cmpxxsi, imm_signed)
362gen_i_cmpxx(gen_cmpxxui, imm_unsigned)
363
364
365static 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
374 return;
375 }
376
377 val = imm(&instr);
378
379 if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
380
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
391gen_i_math_logic(addi, addi, 1, imm_signed)
392gen_i_math_logic(muli, muli, 0, imm_signed)
393
394gen_i_math_logic(andi, andi, 0, imm_unsigned)
395gen_i_math_logic(ori, ori, 1, imm_unsigned)
396gen_i_math_logic(xori, xori, 1, imm_unsigned)
397
398gen_i_math_logic(andhi, andi, 0, imm_shifted)
399gen_i_math_logic(orhi , ori, 1, imm_shifted)
400gen_i_math_logic(xorhi, xori, 1, imm_shifted)
401
402
403static 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
424static void handle_r_type_instr(DisasContext *dc, uint32_t code,
425 uint32_t flags);
426
427static const Nios2Instruction i_type_instructions[] = {
428 INSTRUCTION(call),
429 INSTRUCTION(jmpi),
430 INSTRUCTION_ILLEGAL(),
431 INSTRUCTION_FLG(gen_ldx, MO_UB),
432 INSTRUCTION(addi),
433 INSTRUCTION_FLG(gen_stx, MO_UB),
434 INSTRUCTION(br),
435 INSTRUCTION_FLG(gen_ldx, MO_SB),
436 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE),
437 INSTRUCTION_ILLEGAL(),
438 INSTRUCTION_ILLEGAL(),
439 INSTRUCTION_FLG(gen_ldx, MO_TEUW),
440 INSTRUCTION(andi),
441 INSTRUCTION_FLG(gen_stx, MO_TEUW),
442 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE),
443 INSTRUCTION_FLG(gen_ldx, MO_TESW),
444 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT),
445 INSTRUCTION_ILLEGAL(),
446 INSTRUCTION_ILLEGAL(),
447 INSTRUCTION_NOP(),
448 INSTRUCTION(ori),
449 INSTRUCTION_FLG(gen_stx, MO_TEUL),
450 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT),
451 INSTRUCTION_FLG(gen_ldx, MO_TEUL),
452 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE),
453 INSTRUCTION_ILLEGAL(),
454 INSTRUCTION_ILLEGAL(),
455 INSTRUCTION_NOP(),
456 INSTRUCTION(xori),
457 INSTRUCTION_ILLEGAL(),
458 INSTRUCTION_FLG(gen_bxx, TCG_COND_NE),
459 INSTRUCTION_ILLEGAL(),
460 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ),
461 INSTRUCTION_ILLEGAL(),
462 INSTRUCTION_ILLEGAL(),
463 INSTRUCTION_FLG(gen_ldx, MO_UB),
464 INSTRUCTION(muli),
465 INSTRUCTION_FLG(gen_stx, MO_UB),
466 INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ),
467 INSTRUCTION_FLG(gen_ldx, MO_SB),
468 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU),
469 INSTRUCTION_ILLEGAL(),
470 INSTRUCTION_ILLEGAL(),
471 INSTRUCTION_FLG(gen_ldx, MO_TEUW),
472 INSTRUCTION(andhi),
473 INSTRUCTION_FLG(gen_stx, MO_TEUW),
474 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU),
475 INSTRUCTION_FLG(gen_ldx, MO_TESW),
476 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU),
477 INSTRUCTION_ILLEGAL(),
478 INSTRUCTION_UNIMPLEMENTED(),
479 INSTRUCTION_NOP(),
480 INSTRUCTION(orhi),
481 INSTRUCTION_FLG(gen_stx, MO_TESL),
482 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU),
483 INSTRUCTION_FLG(gen_ldx, MO_TEUL),
484 INSTRUCTION(rdprs),
485 INSTRUCTION_ILLEGAL(),
486 INSTRUCTION_FLG(handle_r_type_instr, 0),
487 INSTRUCTION_NOP(),
488 INSTRUCTION(xorhi),
489 INSTRUCTION_ILLEGAL(),
490 INSTRUCTION_ILLEGAL(),
491 INSTRUCTION_ILLEGAL(),
492};
493
494
495
496
497
498
499
500
501static 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
522static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
523{
524 gen_jumpr(dc, R_RA, false);
525}
526
527
528
529
530
531static 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
549static 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
557static 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
566
567
568static 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
576static 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
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
598
599
600
601
602
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
619static 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
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
652 dc->base.is_jmp = DISAS_UPDATE;
653
654 default:
655 if (wr == -1) {
656
657 tcg_gen_st_tl(v, cpu_env, ofs);
658 } else {
659
660
661
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
682static 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
700
701
702
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
712static 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
720static 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
726static 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
740gen_rr_math_logic(add, add)
741gen_rr_math_logic(sub, sub)
742gen_rr_math_logic(mul, mul)
743
744gen_rr_math_logic(and, and)
745gen_rr_math_logic(or, or)
746gen_rr_math_logic(xor, xor)
747gen_rr_math_logic(nor, nor)
748
749gen_ri_math_logic(srai, sari)
750gen_ri_math_logic(srli, shri)
751gen_ri_math_logic(slli, shli)
752gen_ri_math_logic(roli, rotli)
753
754static 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
767gen_rr_mul_high(mulxss, muls2)
768gen_rr_mul_high(mulxuu, mulu2)
769gen_rr_mul_high(mulxsu, mulsu2)
770
771static 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
784gen_rr_shift(sra, sar)
785gen_rr_shift(srl, shr)
786gen_rr_shift(sll, shl)
787gen_rr_shift(rol, rotl)
788gen_rr_shift(ror, rotr)
789
790static 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
797static 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
804static void trap(DisasContext *dc, uint32_t code, uint32_t flags)
805{
806#ifdef CONFIG_USER_ONLY
807
808
809
810
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
819static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags)
820{
821#ifndef CONFIG_USER_ONLY
822
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
834static const Nios2Instruction r_type_instructions[] = {
835 INSTRUCTION_ILLEGAL(),
836 INSTRUCTION(eret),
837 INSTRUCTION(roli),
838 INSTRUCTION(rol),
839 INSTRUCTION_NOP(),
840 INSTRUCTION(ret),
841 INSTRUCTION(nor),
842 INSTRUCTION(mulxuu),
843 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),
844 INSTRUCTION(bret),
845 INSTRUCTION_ILLEGAL(),
846 INSTRUCTION(ror),
847 INSTRUCTION_NOP(),
848 INSTRUCTION(jmp),
849 INSTRUCTION(and),
850 INSTRUCTION_ILLEGAL(),
851 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),
852 INSTRUCTION_ILLEGAL(),
853 INSTRUCTION(slli),
854 INSTRUCTION(sll),
855 INSTRUCTION(wrprs),
856 INSTRUCTION_ILLEGAL(),
857 INSTRUCTION(or),
858 INSTRUCTION(mulxsu),
859 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),
860 INSTRUCTION_ILLEGAL(),
861 INSTRUCTION(srli),
862 INSTRUCTION(srl),
863 INSTRUCTION(nextpc),
864 INSTRUCTION(callr),
865 INSTRUCTION(xor),
866 INSTRUCTION(mulxss),
867 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),
868 INSTRUCTION_ILLEGAL(),
869 INSTRUCTION_ILLEGAL(),
870 INSTRUCTION_ILLEGAL(),
871 INSTRUCTION(divu),
872 INSTRUCTION(divs),
873 INSTRUCTION(rdctl),
874 INSTRUCTION(mul),
875 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),
876 INSTRUCTION_NOP(),
877 INSTRUCTION_ILLEGAL(),
878 INSTRUCTION_ILLEGAL(),
879 INSTRUCTION_ILLEGAL(),
880 INSTRUCTION(trap),
881 INSTRUCTION(wrctl),
882 INSTRUCTION_ILLEGAL(),
883 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),
884 INSTRUCTION(add),
885 INSTRUCTION_ILLEGAL(),
886 INSTRUCTION_ILLEGAL(),
887 INSTRUCTION(gen_break),
888 INSTRUCTION_ILLEGAL(),
889 INSTRUCTION(nop),
890 INSTRUCTION_ILLEGAL(),
891 INSTRUCTION_ILLEGAL(),
892 INSTRUCTION(sub),
893 INSTRUCTION(srai),
894 INSTRUCTION(sra),
895 INSTRUCTION_ILLEGAL(),
896 INSTRUCTION_ILLEGAL(),
897 INSTRUCTION_ILLEGAL(),
898 INSTRUCTION_ILLEGAL(),
899};
900
901static 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
916illegal_op:
917 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
918}
919
920static 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
932static 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
945static 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
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
962static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
963{
964}
965
966static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
967{
968 tcg_gen_insn_start(dcbase->pc_next);
969}
970
971static 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
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
998static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
999{
1000 DisasContext *dc = container_of(dcbase, DisasContext, base);
1001
1002
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
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
1016 break;
1017
1018 default:
1019 g_assert_not_reached();
1020 }
1021}
1022
1023static 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
1030static 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
1039void 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
1046void 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
1085void 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}
1110