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