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-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
36/* is_jmp field values */
37#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
38#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
39#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
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/* Special R-Type instruction opcode */
52#define INSN_R_TYPE 0x3A
53
54/* I-Type instruction parsing */
55#define I_TYPE(instr, code) \
56 struct { \
57 uint8_t op; \
58 union { \
59 uint16_t u; \
60 int16_t s; \
61 } imm16; \
62 uint8_t b; \
63 uint8_t a; \
64 } (instr) = { \
65 .op = extract32((code), 0, 6), \
66 .imm16.u = extract32((code), 6, 16), \
67 .b = extract32((code), 22, 5), \
68 .a = extract32((code), 27, 5), \
69 }
70
71/* R-Type instruction parsing */
72#define R_TYPE(instr, code) \
73 struct { \
74 uint8_t op; \
75 uint8_t imm5; \
76 uint8_t opx; \
77 uint8_t c; \
78 uint8_t b; \
79 uint8_t a; \
80 } (instr) = { \
81 .op = extract32((code), 0, 6), \
82 .imm5 = extract32((code), 6, 5), \
83 .opx = extract32((code), 11, 6), \
84 .c = extract32((code), 17, 5), \
85 .b = extract32((code), 22, 5), \
86 .a = extract32((code), 27, 5), \
87 }
88
89/* J-Type instruction parsing */
90#define J_TYPE(instr, code) \
91 struct { \
92 uint8_t op; \
93 uint32_t imm26; \
94 } (instr) = { \
95 .op = extract32((code), 0, 6), \
96 .imm26 = extract32((code), 6, 26), \
97 }
98
99typedef struct DisasContext {
100 TCGv_ptr cpu_env;
101 TCGv *cpu_R;
102 TCGv_i32 zero;
103 int is_jmp;
104 target_ulong pc;
105 TranslationBlock *tb;
106 int mem_idx;
107 bool singlestep_enabled;
108} DisasContext;
109
110typedef struct Nios2Instruction {
111 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
112 uint32_t flags;
113} Nios2Instruction;
114
115static uint8_t get_opcode(uint32_t code)
116{
117 I_TYPE(instr, code);
118 return instr.op;
119}
120
121static uint8_t get_opxcode(uint32_t code)
122{
123 R_TYPE(instr, code);
124 return instr.opx;
125}
126
127static TCGv load_zero(DisasContext *dc)
128{
129 if (!dc->zero) {
130 dc->zero = tcg_const_i32(0);
131 }
132 return dc->zero;
133}
134
135static TCGv load_gpr(DisasContext *dc, uint8_t reg)
136{
137 if (likely(reg != R_ZERO)) {
138 return dc->cpu_R[reg];
139 } else {
140 return load_zero(dc);
141 }
142}
143
144static void t_gen_helper_raise_exception(DisasContext *dc,
145 uint32_t index)
146{
147 TCGv_i32 tmp = tcg_const_i32(index);
148
149 tcg_gen_movi_tl(dc->cpu_R[R_PC], dc->pc);
150 gen_helper_raise_exception(dc->cpu_env, tmp);
151 tcg_temp_free_i32(tmp);
152 dc->is_jmp = DISAS_UPDATE;
153}
154
155static bool use_goto_tb(DisasContext *dc, uint32_t dest)
156{
157 if (unlikely(dc->singlestep_enabled)) {
158 return false;
159 }
160
161#ifndef CONFIG_USER_ONLY
162 return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
163#else
164 return true;
165#endif
166}
167
168static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
169{
170 TranslationBlock *tb = dc->tb;
171
172 if (use_goto_tb(dc, dest)) {
173 tcg_gen_goto_tb(n);
174 tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
175 tcg_gen_exit_tb(tb, n);
176 } else {
177 tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
178 tcg_gen_exit_tb(NULL, 0);
179 }
180}
181
182static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
183{
184 t_gen_helper_raise_exception(dc, flags);
185}
186
187static void gen_check_supervisor(DisasContext *dc)
188{
189 if (dc->tb->flags & CR_STATUS_U) {
190 /* CPU in user mode, privileged instruction called, stop. */
191 t_gen_helper_raise_exception(dc, EXCP_SUPERI);
192 }
193}
194
195/*
196 * Used as a placeholder for all instructions which do not have
197 * an effect on the simulator (e.g. flush, sync)
198 */
199static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
200{
201 /* Nothing to do here */
202}
203
204/*
205 * J-Type instructions
206 */
207static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
208{
209 J_TYPE(instr, code);
210 gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
211 dc->is_jmp = DISAS_TB_JUMP;
212}
213
214static void call(DisasContext *dc, uint32_t code, uint32_t flags)
215{
216 tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
217 jmpi(dc, code, flags);
218}
219
220/*
221 * I-Type instructions
222 */
223/* Load instructions */
224static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
225{
226 I_TYPE(instr, code);
227
228 TCGv addr = tcg_temp_new();
229 TCGv data;
230
231 /*
232 * WARNING: Loads into R_ZERO are ignored, but we must generate the
233 * memory access itself to emulate the CPU precisely. Load
234 * from a protected page to R_ZERO will cause SIGSEGV on
235 * the Nios2 CPU.
236 */
237 if (likely(instr.b != R_ZERO)) {
238 data = dc->cpu_R[instr.b];
239 } else {
240 data = tcg_temp_new();
241 }
242
243 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
244 tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
245
246 if (unlikely(instr.b == R_ZERO)) {
247 tcg_temp_free(data);
248 }
249
250 tcg_temp_free(addr);
251}
252
253/* Store instructions */
254static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
255{
256 I_TYPE(instr, code);
257 TCGv val = load_gpr(dc, instr.b);
258
259 TCGv addr = tcg_temp_new();
260 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
261 tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
262 tcg_temp_free(addr);
263}
264
265/* Branch instructions */
266static void br(DisasContext *dc, uint32_t code, uint32_t flags)
267{
268 I_TYPE(instr, code);
269
270 gen_goto_tb(dc, 0, dc->pc + 4 + (instr.imm16.s & -4));
271 dc->is_jmp = DISAS_TB_JUMP;
272}
273
274static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
275{
276 I_TYPE(instr, code);
277
278 TCGLabel *l1 = gen_new_label();
279 tcg_gen_brcond_tl(flags, dc->cpu_R[instr.a], dc->cpu_R[instr.b], l1);
280 gen_goto_tb(dc, 0, dc->pc + 4);
281 gen_set_label(l1);
282 gen_goto_tb(dc, 1, dc->pc + 4 + (instr.imm16.s & -4));
283 dc->is_jmp = DISAS_TB_JUMP;
284}
285
286/* Comparison instructions */
287#define gen_i_cmpxx(fname, op3) \
288static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
289{ \
290 I_TYPE(instr, (code)); \
291 tcg_gen_setcondi_tl(flags, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
292 (op3)); \
293}
294
295gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s)
296gen_i_cmpxx(gen_cmpxxui, instr.imm16.u)
297
298/* Math/logic instructions */
299#define gen_i_math_logic(fname, insn, resimm, op3) \
300static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
301{ \
302 I_TYPE(instr, (code)); \
303 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
304 return; \
305 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
306 tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0); \
307 } else { \
308 tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
309 (op3)); \
310 } \
311}
312
313gen_i_math_logic(addi, addi, 1, instr.imm16.s)
314gen_i_math_logic(muli, muli, 0, instr.imm16.s)
315
316gen_i_math_logic(andi, andi, 0, instr.imm16.u)
317gen_i_math_logic(ori, ori, 1, instr.imm16.u)
318gen_i_math_logic(xori, xori, 1, instr.imm16.u)
319
320gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16)
321gen_i_math_logic(orhi , ori, 1, instr.imm16.u << 16)
322gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16)
323
324/* Prototype only, defined below */
325static void handle_r_type_instr(DisasContext *dc, uint32_t code,
326 uint32_t flags);
327
328static const Nios2Instruction i_type_instructions[] = {
329 INSTRUCTION(call), /* call */
330 INSTRUCTION(jmpi), /* jmpi */
331 INSTRUCTION_ILLEGAL(),
332 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */
333 INSTRUCTION(addi), /* addi */
334 INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */
335 INSTRUCTION(br), /* br */
336 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */
337 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */
338 INSTRUCTION_ILLEGAL(),
339 INSTRUCTION_ILLEGAL(),
340 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhu */
341 INSTRUCTION(andi), /* andi */
342 INSTRUCTION_FLG(gen_stx, MO_UW), /* sth */
343 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */
344 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldh */
345 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */
346 INSTRUCTION_ILLEGAL(),
347 INSTRUCTION_ILLEGAL(),
348 INSTRUCTION_NOP(), /* initda */
349 INSTRUCTION(ori), /* ori */
350 INSTRUCTION_FLG(gen_stx, MO_UL), /* stw */
351 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */
352 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldw */
353 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */
354 INSTRUCTION_ILLEGAL(),
355 INSTRUCTION_ILLEGAL(),
356 INSTRUCTION_NOP(), /* flushda */
357 INSTRUCTION(xori), /* xori */
358 INSTRUCTION_ILLEGAL(),
359 INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */
360 INSTRUCTION_ILLEGAL(),
361 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */
362 INSTRUCTION_ILLEGAL(),
363 INSTRUCTION_ILLEGAL(),
364 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */
365 INSTRUCTION(muli), /* muli */
366 INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */
367 INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */
368 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */
369 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */
370 INSTRUCTION_ILLEGAL(),
371 INSTRUCTION_ILLEGAL(),
372 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhuio */
373 INSTRUCTION(andhi), /* andhi */
374 INSTRUCTION_FLG(gen_stx, MO_UW), /* sthio */
375 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */
376 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldhio */
377 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */
378 INSTRUCTION_ILLEGAL(),
379 INSTRUCTION_UNIMPLEMENTED(), /* custom */
380 INSTRUCTION_NOP(), /* initd */
381 INSTRUCTION(orhi), /* orhi */
382 INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */
383 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */
384 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */
385 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
386 INSTRUCTION_ILLEGAL(),
387 INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */
388 INSTRUCTION_NOP(), /* flushd */
389 INSTRUCTION(xorhi), /* xorhi */
390 INSTRUCTION_ILLEGAL(),
391 INSTRUCTION_ILLEGAL(),
392 INSTRUCTION_ILLEGAL(),
393};
394
395/*
396 * R-Type instructions
397 */
398/*
399 * status <- estatus
400 * PC <- ea
401 */
402static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
403{
404 tcg_gen_mov_tl(dc->cpu_R[CR_STATUS], dc->cpu_R[CR_ESTATUS]);
405 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_EA]);
406
407 dc->is_jmp = DISAS_JUMP;
408}
409
410/* PC <- ra */
411static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
412{
413 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_RA]);
414
415 dc->is_jmp = DISAS_JUMP;
416}
417
418/* PC <- ba */
419static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
420{
421 tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_BA]);
422
423 dc->is_jmp = DISAS_JUMP;
424}
425
426/* PC <- rA */
427static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
428{
429 R_TYPE(instr, code);
430
431 tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
432
433 dc->is_jmp = DISAS_JUMP;
434}
435
436/* rC <- PC + 4 */
437static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
438{
439 R_TYPE(instr, code);
440
441 if (likely(instr.c != R_ZERO)) {
442 tcg_gen_movi_tl(dc->cpu_R[instr.c], dc->pc + 4);
443 }
444}
445
446/*
447 * ra <- PC + 4
448 * PC <- rA
449 */
450static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
451{
452 R_TYPE(instr, code);
453
454 tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
455 tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
456
457 dc->is_jmp = DISAS_JUMP;
458}
459
460/* rC <- ctlN */
461static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
462{
463 R_TYPE(instr, code);
464
465 gen_check_supervisor(dc);
466
467 switch (instr.imm5 + CR_BASE) {
468 case CR_PTEADDR:
469 case CR_TLBACC:
470 case CR_TLBMISC:
471 {
472#if !defined(CONFIG_USER_ONLY)
473 if (likely(instr.c != R_ZERO)) {
474 tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
475#ifdef DEBUG_MMU
476 TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
477 gen_helper_mmu_read_debug(dc->cpu_R[instr.c], dc->cpu_env, tmp);
478 tcg_temp_free_i32(tmp);
479#endif
480 }
481#endif
482 break;
483 }
484
485 default:
486 if (likely(instr.c != R_ZERO)) {
487 tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
488 }
489 break;
490 }
491}
492
493/* ctlN <- rA */
494static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
495{
496 R_TYPE(instr, code);
497
498 gen_check_supervisor(dc);
499
500 switch (instr.imm5 + CR_BASE) {
501 case CR_PTEADDR:
502 case CR_TLBACC:
503 case CR_TLBMISC:
504 {
505#if !defined(CONFIG_USER_ONLY)
506 TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
507 gen_helper_mmu_write(dc->cpu_env, tmp, load_gpr(dc, instr.a));
508 tcg_temp_free_i32(tmp);
509#endif
510 break;
511 }
512
513 default:
514 tcg_gen_mov_tl(dc->cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a));
515 break;
516 }
517
518 /* If interrupts were enabled using WRCTL, trigger them. */
519#if !defined(CONFIG_USER_ONLY)
520 if ((instr.imm5 + CR_BASE) == CR_STATUS) {
521 gen_helper_check_interrupts(dc->cpu_env);
522 }
523#endif
524}
525
526/* Comparison instructions */
527static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
528{
529 R_TYPE(instr, code);
530 if (likely(instr.c != R_ZERO)) {
531 tcg_gen_setcond_tl(flags, dc->cpu_R[instr.c], dc->cpu_R[instr.a],
532 dc->cpu_R[instr.b]);
533 }
534}
535
536/* Math/logic instructions */
537#define gen_r_math_logic(fname, insn, op3) \
538static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
539{ \
540 R_TYPE(instr, (code)); \
541 if (likely(instr.c != R_ZERO)) { \
542 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), \
543 (op3)); \
544 } \
545}
546
547gen_r_math_logic(add, add_tl, load_gpr(dc, instr.b))
548gen_r_math_logic(sub, sub_tl, load_gpr(dc, instr.b))
549gen_r_math_logic(mul, mul_tl, load_gpr(dc, instr.b))
550
551gen_r_math_logic(and, and_tl, load_gpr(dc, instr.b))
552gen_r_math_logic(or, or_tl, load_gpr(dc, instr.b))
553gen_r_math_logic(xor, xor_tl, load_gpr(dc, instr.b))
554gen_r_math_logic(nor, nor_tl, load_gpr(dc, instr.b))
555
556gen_r_math_logic(srai, sari_tl, instr.imm5)
557gen_r_math_logic(srli, shri_tl, instr.imm5)
558gen_r_math_logic(slli, shli_tl, instr.imm5)
559gen_r_math_logic(roli, rotli_tl, instr.imm5)
560
561#define gen_r_mul(fname, insn) \
562static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
563{ \
564 R_TYPE(instr, (code)); \
565 if (likely(instr.c != R_ZERO)) { \
566 TCGv t0 = tcg_temp_new(); \
567 tcg_gen_##insn(t0, dc->cpu_R[instr.c], \
568 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
569 tcg_temp_free(t0); \
570 } \
571}
572
573gen_r_mul(mulxss, muls2_tl)
574gen_r_mul(mulxuu, mulu2_tl)
575gen_r_mul(mulxsu, mulsu2_tl)
576
577#define gen_r_shift_s(fname, insn) \
578static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
579{ \
580 R_TYPE(instr, (code)); \
581 if (likely(instr.c != R_ZERO)) { \
582 TCGv t0 = tcg_temp_new(); \
583 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
584 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
585 tcg_temp_free(t0); \
586 } \
587}
588
589gen_r_shift_s(sra, sar_tl)
590gen_r_shift_s(srl, shr_tl)
591gen_r_shift_s(sll, shl_tl)
592gen_r_shift_s(rol, rotl_tl)
593gen_r_shift_s(ror, rotr_tl)
594
595static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
596{
597 R_TYPE(instr, (code));
598
599 /* Stores into R_ZERO are ignored */
600 if (unlikely(instr.c == R_ZERO)) {
601 return;
602 }
603
604 TCGv t0 = tcg_temp_new();
605 TCGv t1 = tcg_temp_new();
606 TCGv t2 = tcg_temp_new();
607 TCGv t3 = tcg_temp_new();
608
609 tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a));
610 tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b));
611 tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
612 tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
613 tcg_gen_and_tl(t2, t2, t3);
614 tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
615 tcg_gen_or_tl(t2, t2, t3);
616 tcg_gen_movi_tl(t3, 0);
617 tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
618 tcg_gen_div_tl(dc->cpu_R[instr.c], t0, t1);
619 tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
620
621 tcg_temp_free(t3);
622 tcg_temp_free(t2);
623 tcg_temp_free(t1);
624 tcg_temp_free(t0);
625}
626
627static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
628{
629 R_TYPE(instr, (code));
630
631 /* Stores into R_ZERO are ignored */
632 if (unlikely(instr.c == R_ZERO)) {
633 return;
634 }
635
636 TCGv t0 = tcg_temp_new();
637 TCGv t1 = tcg_temp_new();
638 TCGv t2 = tcg_const_tl(0);
639 TCGv t3 = tcg_const_tl(1);
640
641 tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
642 tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
643 tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
644 tcg_gen_divu_tl(dc->cpu_R[instr.c], t0, t1);
645 tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
646
647 tcg_temp_free(t3);
648 tcg_temp_free(t2);
649 tcg_temp_free(t1);
650 tcg_temp_free(t0);
651}
652
653static const Nios2Instruction r_type_instructions[] = {
654 INSTRUCTION_ILLEGAL(),
655 INSTRUCTION(eret), /* eret */
656 INSTRUCTION(roli), /* roli */
657 INSTRUCTION(rol), /* rol */
658 INSTRUCTION_NOP(), /* flushp */
659 INSTRUCTION(ret), /* ret */
660 INSTRUCTION(nor), /* nor */
661 INSTRUCTION(mulxuu), /* mulxuu */
662 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */
663 INSTRUCTION(bret), /* bret */
664 INSTRUCTION_ILLEGAL(),
665 INSTRUCTION(ror), /* ror */
666 INSTRUCTION_NOP(), /* flushi */
667 INSTRUCTION(jmp), /* jmp */
668 INSTRUCTION(and), /* and */
669 INSTRUCTION_ILLEGAL(),
670 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */
671 INSTRUCTION_ILLEGAL(),
672 INSTRUCTION(slli), /* slli */
673 INSTRUCTION(sll), /* sll */
674 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
675 INSTRUCTION_ILLEGAL(),
676 INSTRUCTION(or), /* or */
677 INSTRUCTION(mulxsu), /* mulxsu */
678 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */
679 INSTRUCTION_ILLEGAL(),
680 INSTRUCTION(srli), /* srli */
681 INSTRUCTION(srl), /* srl */
682 INSTRUCTION(nextpc), /* nextpc */
683 INSTRUCTION(callr), /* callr */
684 INSTRUCTION(xor), /* xor */
685 INSTRUCTION(mulxss), /* mulxss */
686 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */
687 INSTRUCTION_ILLEGAL(),
688 INSTRUCTION_ILLEGAL(),
689 INSTRUCTION_ILLEGAL(),
690 INSTRUCTION(divu), /* divu */
691 INSTRUCTION(divs), /* div */
692 INSTRUCTION(rdctl), /* rdctl */
693 INSTRUCTION(mul), /* mul */
694 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */
695 INSTRUCTION_NOP(), /* initi */
696 INSTRUCTION_ILLEGAL(),
697 INSTRUCTION_ILLEGAL(),
698 INSTRUCTION_ILLEGAL(),
699 INSTRUCTION_FLG(gen_excp, EXCP_TRAP), /* trap */
700 INSTRUCTION(wrctl), /* wrctl */
701 INSTRUCTION_ILLEGAL(),
702 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */
703 INSTRUCTION(add), /* add */
704 INSTRUCTION_ILLEGAL(),
705 INSTRUCTION_ILLEGAL(),
706 INSTRUCTION_FLG(gen_excp, EXCP_BREAK), /* break */
707 INSTRUCTION_ILLEGAL(),
708 INSTRUCTION(nop), /* nop */
709 INSTRUCTION_ILLEGAL(),
710 INSTRUCTION_ILLEGAL(),
711 INSTRUCTION(sub), /* sub */
712 INSTRUCTION(srai), /* srai */
713 INSTRUCTION(sra), /* sra */
714 INSTRUCTION_ILLEGAL(),
715 INSTRUCTION_ILLEGAL(),
716 INSTRUCTION_ILLEGAL(),
717 INSTRUCTION_ILLEGAL(),
718};
719
720static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
721{
722 uint8_t opx;
723 const Nios2Instruction *instr;
724
725 opx = get_opxcode(code);
726 if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
727 goto illegal_op;
728 }
729
730 instr = &r_type_instructions[opx];
731 instr->handler(dc, code, instr->flags);
732
733 return;
734
735illegal_op:
736 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
737}
738
739static void handle_instruction(DisasContext *dc, CPUNios2State *env)
740{
741 uint32_t code;
742 uint8_t op;
743 const Nios2Instruction *instr;
744#if defined(CONFIG_USER_ONLY)
745 /* FIXME: Is this needed ? */
746 if (dc->pc >= 0x1000 && dc->pc < 0x2000) {
747 env->regs[R_PC] = dc->pc;
748 t_gen_helper_raise_exception(dc, 0xaa);
749 return;
750 }
751#endif
752 code = cpu_ldl_code(env, dc->pc);
753 op = get_opcode(code);
754
755 if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
756 goto illegal_op;
757 }
758
759 dc->zero = NULL;
760
761 instr = &i_type_instructions[op];
762 instr->handler(dc, code, instr->flags);
763
764 if (dc->zero) {
765 tcg_temp_free(dc->zero);
766 }
767
768 return;
769
770illegal_op:
771 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
772}
773
774static const char * const regnames[] = {
775 "zero", "at", "r2", "r3",
776 "r4", "r5", "r6", "r7",
777 "r8", "r9", "r10", "r11",
778 "r12", "r13", "r14", "r15",
779 "r16", "r17", "r18", "r19",
780 "r20", "r21", "r22", "r23",
781 "et", "bt", "gp", "sp",
782 "fp", "ea", "ba", "ra",
783 "status", "estatus", "bstatus", "ienable",
784 "ipending", "cpuid", "reserved0", "exception",
785 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
786 "badaddr", "config", "mpubase", "mpuacc",
787 "reserved2", "reserved3", "reserved4", "reserved5",
788 "reserved6", "reserved7", "reserved8", "reserved9",
789 "reserved10", "reserved11", "reserved12", "reserved13",
790 "reserved14", "reserved15", "reserved16", "reserved17",
791 "rpc"
792};
793
794static TCGv cpu_R[NUM_CORE_REGS];
795
796#include "exec/gen-icount.h"
797
798static void gen_exception(DisasContext *dc, uint32_t excp)
799{
800 TCGv_i32 tmp = tcg_const_i32(excp);
801
802 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
803 gen_helper_raise_exception(cpu_env, tmp);
804 tcg_temp_free_i32(tmp);
805 dc->is_jmp = DISAS_UPDATE;
806}
807
808/* generate intermediate code for basic block 'tb'. */
809void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
810{
811 CPUNios2State *env = cs->env_ptr;
812 DisasContext dc1, *dc = &dc1;
813 int num_insns;
814
815 /* Initialize DC */
816 dc->cpu_env = cpu_env;
817 dc->cpu_R = cpu_R;
818 dc->is_jmp = DISAS_NEXT;
819 dc->pc = tb->pc;
820 dc->tb = tb;
821 dc->mem_idx = cpu_mmu_index(env, false);
822 dc->singlestep_enabled = cs->singlestep_enabled;
823
824 /* Set up instruction counts */
825 num_insns = 0;
826 if (max_insns > 1) {
827 int page_insns = (TARGET_PAGE_SIZE - (tb->pc & TARGET_PAGE_MASK)) / 4;
828 if (max_insns > page_insns) {
829 max_insns = page_insns;
830 }
831 }
832
833 gen_tb_start(tb);
834 do {
835 tcg_gen_insn_start(dc->pc);
836 num_insns++;
837
838 if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
839 gen_exception(dc, EXCP_DEBUG);
840 /* The address covered by the breakpoint must be included in
841 [tb->pc, tb->pc + tb->size) in order to for it to be
842 properly cleared -- thus we increment the PC here so that
843 the logic setting tb->size below does the right thing. */
844 dc->pc += 4;
845 break;
846 }
847
848 if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
849 gen_io_start();
850 }
851
852 /* Decode an instruction */
853 handle_instruction(dc, env);
854
855 dc->pc += 4;
856
857 /* Translation stops when a conditional branch is encountered.
858 * Otherwise the subsequent code could get translated several times.
859 * Also stop translation when a page boundary is reached. This
860 * ensures prefetch aborts occur at the right place. */
861 } while (!dc->is_jmp &&
862 !tcg_op_buf_full() &&
863 num_insns < max_insns);
864
865 /* Indicate where the next block should start */
866 switch (dc->is_jmp) {
867 case DISAS_NEXT:
868 /* Save the current PC back into the CPU register */
869 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
870 tcg_gen_exit_tb(NULL, 0);
871 break;
872
873 default:
874 case DISAS_JUMP:
875 case DISAS_UPDATE:
876 /* The jump will already have updated the PC register */
877 tcg_gen_exit_tb(NULL, 0);
878 break;
879
880 case DISAS_TB_JUMP:
881 /* nothing more to generate */
882 break;
883 }
884
885 /* End off the block */
886 gen_tb_end(tb, num_insns);
887
888 /* Mark instruction starts for the final generated instruction */
889 tb->size = dc->pc - tb->pc;
890 tb->icount = num_insns;
891
892#ifdef DEBUG_DISAS
893 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
894 && qemu_log_in_addr_range(tb->pc)) {
895 qemu_log_lock();
896 qemu_log("IN: %s\n", lookup_symbol(tb->pc));
897 log_target_disas(cs, tb->pc, dc->pc - tb->pc);
898 qemu_log("\n");
899 qemu_log_unlock();
900 }
901#endif
902}
903
904void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
905{
906 Nios2CPU *cpu = NIOS2_CPU(cs);
907 CPUNios2State *env = &cpu->env;
908 int i;
909
910 if (!env) {
911 return;
912 }
913
914 qemu_fprintf(f, "IN: PC=%x %s\n",
915 env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
916
917 for (i = 0; i < NUM_CORE_REGS; i++) {
918 qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
919 if ((i + 1) % 4 == 0) {
920 qemu_fprintf(f, "\n");
921 }
922 }
923#if !defined(CONFIG_USER_ONLY)
924 qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
925 env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
926 (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
927 env->mmu.tlbacc_wr);
928#endif
929 qemu_fprintf(f, "\n\n");
930}
931
932void nios2_tcg_init(void)
933{
934 int i;
935
936 for (i = 0; i < NUM_CORE_REGS; i++) {
937 cpu_R[i] = tcg_global_mem_new(cpu_env,
938 offsetof(CPUNios2State, regs[i]),
939 regnames[i]);
940 }
941}
942
943void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
944 target_ulong *data)
945{
946 env->regs[R_PC] = data[0];
947}
948