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