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