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