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