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