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