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