2 * Altera Nios II emulation for qemu: main translation routines.
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.)
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.
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.
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>
24 #include "qemu/osdep.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"
32 #include "exec/cpu_ldst.h"
33 #include "exec/translator.h"
34 #include "qemu/qemu-print.h"
36 /* is_jmp field values */
37 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
38 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
39 #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
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)
51 /* Special R-Type instruction opcode */
52 #define INSN_R_TYPE 0x3A
54 /* I-Type instruction parsing */
55 #define I_TYPE(instr, code) \
65 .op = extract32((code), 0, 6), \
66 .imm16.u = extract32((code), 6, 16), \
67 .b = extract32((code), 22, 5), \
68 .a = extract32((code), 27, 5), \
71 /* R-Type instruction parsing */
72 #define R_TYPE(instr, code) \
81 .op = extract32((code), 0, 6), \
82 .imm5 = extract32((code), 6, 5), \
83 .opx = extract32((code), 11, 6), \
84 .c = extract32((code), 17, 5), \
85 .b = extract32((code), 22, 5), \
86 .a = extract32((code), 27, 5), \
89 /* J-Type instruction parsing */
90 #define J_TYPE(instr, code) \
95 .op = extract32((code), 0, 6), \
96 .imm26 = extract32((code), 6, 26), \
99 typedef struct DisasContext
{
105 TranslationBlock
*tb
;
107 bool singlestep_enabled
;
110 typedef struct Nios2Instruction
{
111 void (*handler
)(DisasContext
*dc
, uint32_t code
, uint32_t flags
);
115 static uint8_t get_opcode(uint32_t code
)
121 static uint8_t get_opxcode(uint32_t code
)
127 static TCGv
load_zero(DisasContext
*dc
)
130 dc
->zero
= tcg_const_i32(0);
135 static TCGv
load_gpr(DisasContext
*dc
, uint8_t reg
)
137 if (likely(reg
!= R_ZERO
)) {
138 return dc
->cpu_R
[reg
];
140 return load_zero(dc
);
144 static void t_gen_helper_raise_exception(DisasContext
*dc
,
147 TCGv_i32 tmp
= tcg_const_i32(index
);
149 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dc
->pc
);
150 gen_helper_raise_exception(dc
->cpu_env
, tmp
);
151 tcg_temp_free_i32(tmp
);
152 dc
->is_jmp
= DISAS_UPDATE
;
155 static bool use_goto_tb(DisasContext
*dc
, uint32_t dest
)
157 if (unlikely(dc
->singlestep_enabled
)) {
161 #ifndef CONFIG_USER_ONLY
162 return (dc
->tb
->pc
& TARGET_PAGE_MASK
) == (dest
& TARGET_PAGE_MASK
);
168 static void gen_goto_tb(DisasContext
*dc
, int n
, uint32_t dest
)
170 TranslationBlock
*tb
= dc
->tb
;
172 if (use_goto_tb(dc
, dest
)) {
174 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dest
);
175 tcg_gen_exit_tb(tb
, n
);
177 tcg_gen_movi_tl(dc
->cpu_R
[R_PC
], dest
);
178 tcg_gen_exit_tb(NULL
, 0);
182 static void gen_excp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
184 t_gen_helper_raise_exception(dc
, flags
);
187 static void gen_check_supervisor(DisasContext
*dc
)
189 if (dc
->tb
->flags
& CR_STATUS_U
) {
190 /* CPU in user mode, privileged instruction called, stop. */
191 t_gen_helper_raise_exception(dc
, EXCP_SUPERI
);
196 * Used as a placeholder for all instructions which do not have
197 * an effect on the simulator (e.g. flush, sync)
199 static void nop(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
201 /* Nothing to do here */
205 * J-Type instructions
207 static void jmpi(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
210 gen_goto_tb(dc
, 0, (dc
->pc
& 0xF0000000) | (instr
.imm26
<< 2));
211 dc
->is_jmp
= DISAS_TB_JUMP
;
214 static void call(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
216 tcg_gen_movi_tl(dc
->cpu_R
[R_RA
], dc
->pc
+ 4);
217 jmpi(dc
, code
, flags
);
221 * I-Type instructions
223 /* Load instructions */
224 static void gen_ldx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
228 TCGv addr
= tcg_temp_new();
232 * WARNING: Loads into R_ZERO are ignored, but we must generate the
233 * memory access itself to emulate the CPU precisely. Load
234 * from a protected page to R_ZERO will cause SIGSEGV on
237 if (likely(instr
.b
!= R_ZERO
)) {
238 data
= dc
->cpu_R
[instr
.b
];
240 data
= tcg_temp_new();
243 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
244 tcg_gen_qemu_ld_tl(data
, addr
, dc
->mem_idx
, flags
);
246 if (unlikely(instr
.b
== R_ZERO
)) {
253 /* Store instructions */
254 static void gen_stx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
257 TCGv val
= load_gpr(dc
, instr
.b
);
259 TCGv addr
= tcg_temp_new();
260 tcg_gen_addi_tl(addr
, load_gpr(dc
, instr
.a
), instr
.imm16
.s
);
261 tcg_gen_qemu_st_tl(val
, addr
, dc
->mem_idx
, flags
);
265 /* Branch instructions */
266 static void br(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
270 gen_goto_tb(dc
, 0, dc
->pc
+ 4 + (instr
.imm16
.s
& -4));
271 dc
->is_jmp
= DISAS_TB_JUMP
;
274 static void gen_bxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
278 TCGLabel
*l1
= gen_new_label();
279 tcg_gen_brcond_tl(flags
, dc
->cpu_R
[instr
.a
], dc
->cpu_R
[instr
.b
], l1
);
280 gen_goto_tb(dc
, 0, dc
->pc
+ 4);
282 gen_goto_tb(dc
, 1, dc
->pc
+ 4 + (instr
.imm16
.s
& -4));
283 dc
->is_jmp
= DISAS_TB_JUMP
;
286 /* Comparison instructions */
287 #define gen_i_cmpxx(fname, op3) \
288 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
290 I_TYPE(instr, (code)); \
291 tcg_gen_setcondi_tl(flags, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
295 gen_i_cmpxx(gen_cmpxxsi
, instr
.imm16
.s
)
296 gen_i_cmpxx(gen_cmpxxui
, instr
.imm16
.u
)
298 /* Math/logic instructions */
299 #define gen_i_math_logic(fname, insn, resimm, op3) \
300 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
302 I_TYPE(instr, (code)); \
303 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \
305 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \
306 tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0); \
308 tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a], \
313 gen_i_math_logic(addi
, addi
, 1, instr
.imm16
.s
)
314 gen_i_math_logic(muli
, muli
, 0, instr
.imm16
.s
)
316 gen_i_math_logic(andi
, andi
, 0, instr
.imm16
.u
)
317 gen_i_math_logic(ori
, ori
, 1, instr
.imm16
.u
)
318 gen_i_math_logic(xori
, xori
, 1, instr
.imm16
.u
)
320 gen_i_math_logic(andhi
, andi
, 0, instr
.imm16
.u
<< 16)
321 gen_i_math_logic(orhi
, ori
, 1, instr
.imm16
.u
<< 16)
322 gen_i_math_logic(xorhi
, xori
, 1, instr
.imm16
.u
<< 16)
324 /* Prototype only, defined below */
325 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
,
328 static const Nios2Instruction i_type_instructions
[] = {
329 INSTRUCTION(call
), /* call */
330 INSTRUCTION(jmpi
), /* jmpi */
331 INSTRUCTION_ILLEGAL(),
332 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbu */
333 INSTRUCTION(addi
), /* addi */
334 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stb */
335 INSTRUCTION(br
), /* br */
336 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldb */
337 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_GE
), /* cmpgei */
338 INSTRUCTION_ILLEGAL(),
339 INSTRUCTION_ILLEGAL(),
340 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhu */
341 INSTRUCTION(andi
), /* andi */
342 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sth */
343 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GE
), /* bge */
344 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldh */
345 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_LT
), /* cmplti */
346 INSTRUCTION_ILLEGAL(),
347 INSTRUCTION_ILLEGAL(),
348 INSTRUCTION_NOP(), /* initda */
349 INSTRUCTION(ori
), /* ori */
350 INSTRUCTION_FLG(gen_stx
, MO_UL
), /* stw */
351 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LT
), /* blt */
352 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldw */
353 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_NE
), /* cmpnei */
354 INSTRUCTION_ILLEGAL(),
355 INSTRUCTION_ILLEGAL(),
356 INSTRUCTION_NOP(), /* flushda */
357 INSTRUCTION(xori
), /* xori */
358 INSTRUCTION_ILLEGAL(),
359 INSTRUCTION_FLG(gen_bxx
, TCG_COND_NE
), /* bne */
360 INSTRUCTION_ILLEGAL(),
361 INSTRUCTION_FLG(gen_cmpxxsi
, TCG_COND_EQ
), /* cmpeqi */
362 INSTRUCTION_ILLEGAL(),
363 INSTRUCTION_ILLEGAL(),
364 INSTRUCTION_FLG(gen_ldx
, MO_UB
), /* ldbuio */
365 INSTRUCTION(muli
), /* muli */
366 INSTRUCTION_FLG(gen_stx
, MO_UB
), /* stbio */
367 INSTRUCTION_FLG(gen_bxx
, TCG_COND_EQ
), /* beq */
368 INSTRUCTION_FLG(gen_ldx
, MO_SB
), /* ldbio */
369 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_GEU
), /* cmpgeui */
370 INSTRUCTION_ILLEGAL(),
371 INSTRUCTION_ILLEGAL(),
372 INSTRUCTION_FLG(gen_ldx
, MO_UW
), /* ldhuio */
373 INSTRUCTION(andhi
), /* andhi */
374 INSTRUCTION_FLG(gen_stx
, MO_UW
), /* sthio */
375 INSTRUCTION_FLG(gen_bxx
, TCG_COND_GEU
), /* bgeu */
376 INSTRUCTION_FLG(gen_ldx
, MO_SW
), /* ldhio */
377 INSTRUCTION_FLG(gen_cmpxxui
, TCG_COND_LTU
), /* cmpltui */
378 INSTRUCTION_ILLEGAL(),
379 INSTRUCTION_UNIMPLEMENTED(), /* custom */
380 INSTRUCTION_NOP(), /* initd */
381 INSTRUCTION(orhi
), /* orhi */
382 INSTRUCTION_FLG(gen_stx
, MO_SL
), /* stwio */
383 INSTRUCTION_FLG(gen_bxx
, TCG_COND_LTU
), /* bltu */
384 INSTRUCTION_FLG(gen_ldx
, MO_UL
), /* ldwio */
385 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
386 INSTRUCTION_ILLEGAL(),
387 INSTRUCTION_FLG(handle_r_type_instr
, 0), /* R-Type */
388 INSTRUCTION_NOP(), /* flushd */
389 INSTRUCTION(xorhi
), /* xorhi */
390 INSTRUCTION_ILLEGAL(),
391 INSTRUCTION_ILLEGAL(),
392 INSTRUCTION_ILLEGAL(),
396 * R-Type instructions
402 static void eret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
404 tcg_gen_mov_tl(dc
->cpu_R
[CR_STATUS
], dc
->cpu_R
[CR_ESTATUS
]);
405 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_EA
]);
407 dc
->is_jmp
= DISAS_JUMP
;
411 static void ret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
413 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_RA
]);
415 dc
->is_jmp
= DISAS_JUMP
;
419 static void bret(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
421 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], dc
->cpu_R
[R_BA
]);
423 dc
->is_jmp
= DISAS_JUMP
;
427 static void jmp(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
431 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
433 dc
->is_jmp
= DISAS_JUMP
;
437 static void nextpc(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
441 if (likely(instr
.c
!= R_ZERO
)) {
442 tcg_gen_movi_tl(dc
->cpu_R
[instr
.c
], dc
->pc
+ 4);
450 static void callr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
454 tcg_gen_mov_tl(dc
->cpu_R
[R_PC
], load_gpr(dc
, instr
.a
));
455 tcg_gen_movi_tl(dc
->cpu_R
[R_RA
], dc
->pc
+ 4);
457 dc
->is_jmp
= DISAS_JUMP
;
461 static void rdctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
465 gen_check_supervisor(dc
);
467 switch (instr
.imm5
+ CR_BASE
) {
472 #if !defined(CONFIG_USER_ONLY)
473 if (likely(instr
.c
!= R_ZERO
)) {
474 tcg_gen_mov_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.imm5
+ CR_BASE
]);
476 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
477 gen_helper_mmu_read_debug(dc
->cpu_R
[instr
.c
], dc
->cpu_env
, tmp
);
478 tcg_temp_free_i32(tmp
);
486 if (likely(instr
.c
!= R_ZERO
)) {
487 tcg_gen_mov_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.imm5
+ CR_BASE
]);
494 static void wrctl(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
498 gen_check_supervisor(dc
);
500 switch (instr
.imm5
+ CR_BASE
) {
505 #if !defined(CONFIG_USER_ONLY)
506 TCGv_i32 tmp
= tcg_const_i32(instr
.imm5
+ CR_BASE
);
507 gen_helper_mmu_write(dc
->cpu_env
, tmp
, load_gpr(dc
, instr
.a
));
508 tcg_temp_free_i32(tmp
);
514 tcg_gen_mov_tl(dc
->cpu_R
[instr
.imm5
+ CR_BASE
], load_gpr(dc
, instr
.a
));
518 /* If interrupts were enabled using WRCTL, trigger them. */
519 #if !defined(CONFIG_USER_ONLY)
520 if ((instr
.imm5
+ CR_BASE
) == CR_STATUS
) {
521 gen_helper_check_interrupts(dc
->cpu_env
);
526 /* Comparison instructions */
527 static void gen_cmpxx(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
530 if (likely(instr
.c
!= R_ZERO
)) {
531 tcg_gen_setcond_tl(flags
, dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.a
],
536 /* Math/logic instructions */
537 #define gen_r_math_logic(fname, insn, op3) \
538 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
540 R_TYPE(instr, (code)); \
541 if (likely(instr.c != R_ZERO)) { \
542 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), \
547 gen_r_math_logic(add
, add_tl
, load_gpr(dc
, instr
.b
))
548 gen_r_math_logic(sub
, sub_tl
, load_gpr(dc
, instr
.b
))
549 gen_r_math_logic(mul
, mul_tl
, load_gpr(dc
, instr
.b
))
551 gen_r_math_logic(and, and_tl
, load_gpr(dc
, instr
.b
))
552 gen_r_math_logic(or, or_tl
, load_gpr(dc
, instr
.b
))
553 gen_r_math_logic(xor, xor_tl
, load_gpr(dc
, instr
.b
))
554 gen_r_math_logic(nor
, nor_tl
, load_gpr(dc
, instr
.b
))
556 gen_r_math_logic(srai
, sari_tl
, instr
.imm5
)
557 gen_r_math_logic(srli
, shri_tl
, instr
.imm5
)
558 gen_r_math_logic(slli
, shli_tl
, instr
.imm5
)
559 gen_r_math_logic(roli
, rotli_tl
, instr
.imm5
)
561 #define gen_r_mul(fname, insn) \
562 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
564 R_TYPE(instr, (code)); \
565 if (likely(instr.c != R_ZERO)) { \
566 TCGv t0 = tcg_temp_new(); \
567 tcg_gen_##insn(t0, dc->cpu_R[instr.c], \
568 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
573 gen_r_mul(mulxss
, muls2_tl
)
574 gen_r_mul(mulxuu
, mulu2_tl
)
575 gen_r_mul(mulxsu
, mulsu2_tl
)
577 #define gen_r_shift_s(fname, insn) \
578 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
580 R_TYPE(instr, (code)); \
581 if (likely(instr.c != R_ZERO)) { \
582 TCGv t0 = tcg_temp_new(); \
583 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \
584 tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
589 gen_r_shift_s(sra
, sar_tl
)
590 gen_r_shift_s(srl
, shr_tl
)
591 gen_r_shift_s(sll
, shl_tl
)
592 gen_r_shift_s(rol
, rotl_tl
)
593 gen_r_shift_s(ror
, rotr_tl
)
595 static void divs(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
597 R_TYPE(instr
, (code
));
599 /* Stores into R_ZERO are ignored */
600 if (unlikely(instr
.c
== R_ZERO
)) {
604 TCGv t0
= tcg_temp_new();
605 TCGv t1
= tcg_temp_new();
606 TCGv t2
= tcg_temp_new();
607 TCGv t3
= tcg_temp_new();
609 tcg_gen_ext32s_tl(t0
, load_gpr(dc
, instr
.a
));
610 tcg_gen_ext32s_tl(t1
, load_gpr(dc
, instr
.b
));
611 tcg_gen_setcondi_tl(TCG_COND_EQ
, t2
, t0
, INT_MIN
);
612 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, -1);
613 tcg_gen_and_tl(t2
, t2
, t3
);
614 tcg_gen_setcondi_tl(TCG_COND_EQ
, t3
, t1
, 0);
615 tcg_gen_or_tl(t2
, t2
, t3
);
616 tcg_gen_movi_tl(t3
, 0);
617 tcg_gen_movcond_tl(TCG_COND_NE
, t1
, t2
, t3
, t2
, t1
);
618 tcg_gen_div_tl(dc
->cpu_R
[instr
.c
], t0
, t1
);
619 tcg_gen_ext32s_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.c
]);
627 static void divu(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
629 R_TYPE(instr
, (code
));
631 /* Stores into R_ZERO are ignored */
632 if (unlikely(instr
.c
== R_ZERO
)) {
636 TCGv t0
= tcg_temp_new();
637 TCGv t1
= tcg_temp_new();
638 TCGv t2
= tcg_const_tl(0);
639 TCGv t3
= tcg_const_tl(1);
641 tcg_gen_ext32u_tl(t0
, load_gpr(dc
, instr
.a
));
642 tcg_gen_ext32u_tl(t1
, load_gpr(dc
, instr
.b
));
643 tcg_gen_movcond_tl(TCG_COND_EQ
, t1
, t1
, t2
, t3
, t1
);
644 tcg_gen_divu_tl(dc
->cpu_R
[instr
.c
], t0
, t1
);
645 tcg_gen_ext32s_tl(dc
->cpu_R
[instr
.c
], dc
->cpu_R
[instr
.c
]);
653 static const Nios2Instruction r_type_instructions
[] = {
654 INSTRUCTION_ILLEGAL(),
655 INSTRUCTION(eret
), /* eret */
656 INSTRUCTION(roli
), /* roli */
657 INSTRUCTION(rol
), /* rol */
658 INSTRUCTION_NOP(), /* flushp */
659 INSTRUCTION(ret
), /* ret */
660 INSTRUCTION(nor
), /* nor */
661 INSTRUCTION(mulxuu
), /* mulxuu */
662 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GE
), /* cmpge */
663 INSTRUCTION(bret
), /* bret */
664 INSTRUCTION_ILLEGAL(),
665 INSTRUCTION(ror
), /* ror */
666 INSTRUCTION_NOP(), /* flushi */
667 INSTRUCTION(jmp
), /* jmp */
668 INSTRUCTION(and), /* and */
669 INSTRUCTION_ILLEGAL(),
670 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LT
), /* cmplt */
671 INSTRUCTION_ILLEGAL(),
672 INSTRUCTION(slli
), /* slli */
673 INSTRUCTION(sll
), /* sll */
674 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
675 INSTRUCTION_ILLEGAL(),
676 INSTRUCTION(or), /* or */
677 INSTRUCTION(mulxsu
), /* mulxsu */
678 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_NE
), /* cmpne */
679 INSTRUCTION_ILLEGAL(),
680 INSTRUCTION(srli
), /* srli */
681 INSTRUCTION(srl
), /* srl */
682 INSTRUCTION(nextpc
), /* nextpc */
683 INSTRUCTION(callr
), /* callr */
684 INSTRUCTION(xor), /* xor */
685 INSTRUCTION(mulxss
), /* mulxss */
686 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_EQ
), /* cmpeq */
687 INSTRUCTION_ILLEGAL(),
688 INSTRUCTION_ILLEGAL(),
689 INSTRUCTION_ILLEGAL(),
690 INSTRUCTION(divu
), /* divu */
691 INSTRUCTION(divs
), /* div */
692 INSTRUCTION(rdctl
), /* rdctl */
693 INSTRUCTION(mul
), /* mul */
694 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_GEU
), /* cmpgeu */
695 INSTRUCTION_NOP(), /* initi */
696 INSTRUCTION_ILLEGAL(),
697 INSTRUCTION_ILLEGAL(),
698 INSTRUCTION_ILLEGAL(),
699 INSTRUCTION_FLG(gen_excp
, EXCP_TRAP
), /* trap */
700 INSTRUCTION(wrctl
), /* wrctl */
701 INSTRUCTION_ILLEGAL(),
702 INSTRUCTION_FLG(gen_cmpxx
, TCG_COND_LTU
), /* cmpltu */
703 INSTRUCTION(add
), /* add */
704 INSTRUCTION_ILLEGAL(),
705 INSTRUCTION_ILLEGAL(),
706 INSTRUCTION_FLG(gen_excp
, EXCP_BREAK
), /* break */
707 INSTRUCTION_ILLEGAL(),
708 INSTRUCTION(nop
), /* nop */
709 INSTRUCTION_ILLEGAL(),
710 INSTRUCTION_ILLEGAL(),
711 INSTRUCTION(sub
), /* sub */
712 INSTRUCTION(srai
), /* srai */
713 INSTRUCTION(sra
), /* sra */
714 INSTRUCTION_ILLEGAL(),
715 INSTRUCTION_ILLEGAL(),
716 INSTRUCTION_ILLEGAL(),
717 INSTRUCTION_ILLEGAL(),
720 static void handle_r_type_instr(DisasContext
*dc
, uint32_t code
, uint32_t flags
)
723 const Nios2Instruction
*instr
;
725 opx
= get_opxcode(code
);
726 if (unlikely(opx
>= ARRAY_SIZE(r_type_instructions
))) {
730 instr
= &r_type_instructions
[opx
];
731 instr
->handler(dc
, code
, instr
->flags
);
736 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
739 static void handle_instruction(DisasContext
*dc
, CPUNios2State
*env
)
743 const Nios2Instruction
*instr
;
744 #if defined(CONFIG_USER_ONLY)
745 /* FIXME: Is this needed ? */
746 if (dc
->pc
>= 0x1000 && dc
->pc
< 0x2000) {
747 env
->regs
[R_PC
] = dc
->pc
;
748 t_gen_helper_raise_exception(dc
, 0xaa);
752 code
= cpu_ldl_code(env
, dc
->pc
);
753 op
= get_opcode(code
);
755 if (unlikely(op
>= ARRAY_SIZE(i_type_instructions
))) {
761 instr
= &i_type_instructions
[op
];
762 instr
->handler(dc
, code
, instr
->flags
);
765 tcg_temp_free(dc
->zero
);
771 t_gen_helper_raise_exception(dc
, EXCP_ILLEGAL
);
774 static const char * const regnames
[] = {
775 "zero", "at", "r2", "r3",
776 "r4", "r5", "r6", "r7",
777 "r8", "r9", "r10", "r11",
778 "r12", "r13", "r14", "r15",
779 "r16", "r17", "r18", "r19",
780 "r20", "r21", "r22", "r23",
781 "et", "bt", "gp", "sp",
782 "fp", "ea", "ba", "ra",
783 "status", "estatus", "bstatus", "ienable",
784 "ipending", "cpuid", "reserved0", "exception",
785 "pteaddr", "tlbacc", "tlbmisc", "reserved1",
786 "badaddr", "config", "mpubase", "mpuacc",
787 "reserved2", "reserved3", "reserved4", "reserved5",
788 "reserved6", "reserved7", "reserved8", "reserved9",
789 "reserved10", "reserved11", "reserved12", "reserved13",
790 "reserved14", "reserved15", "reserved16", "reserved17",
794 static TCGv cpu_R
[NUM_CORE_REGS
];
796 #include "exec/gen-icount.h"
798 static void gen_exception(DisasContext
*dc
, uint32_t excp
)
800 TCGv_i32 tmp
= tcg_const_i32(excp
);
802 tcg_gen_movi_tl(cpu_R
[R_PC
], dc
->pc
);
803 gen_helper_raise_exception(cpu_env
, tmp
);
804 tcg_temp_free_i32(tmp
);
805 dc
->is_jmp
= DISAS_UPDATE
;
808 /* generate intermediate code for basic block 'tb'. */
809 void gen_intermediate_code(CPUState
*cs
, TranslationBlock
*tb
, int max_insns
)
811 CPUNios2State
*env
= cs
->env_ptr
;
812 DisasContext dc1
, *dc
= &dc1
;
816 dc
->cpu_env
= cpu_env
;
818 dc
->is_jmp
= DISAS_NEXT
;
821 dc
->mem_idx
= cpu_mmu_index(env
, false);
822 dc
->singlestep_enabled
= cs
->singlestep_enabled
;
824 /* Set up instruction counts */
827 int page_insns
= (TARGET_PAGE_SIZE
- (tb
->pc
& TARGET_PAGE_MASK
)) / 4;
828 if (max_insns
> page_insns
) {
829 max_insns
= page_insns
;
835 tcg_gen_insn_start(dc
->pc
);
838 if (unlikely(cpu_breakpoint_test(cs
, dc
->pc
, BP_ANY
))) {
839 gen_exception(dc
, EXCP_DEBUG
);
840 /* The address covered by the breakpoint must be included in
841 [tb->pc, tb->pc + tb->size) in order to for it to be
842 properly cleared -- thus we increment the PC here so that
843 the logic setting tb->size below does the right thing. */
848 if (num_insns
== max_insns
&& (tb_cflags(tb
) & CF_LAST_IO
)) {
852 /* Decode an instruction */
853 handle_instruction(dc
, env
);
857 /* Translation stops when a conditional branch is encountered.
858 * Otherwise the subsequent code could get translated several times.
859 * Also stop translation when a page boundary is reached. This
860 * ensures prefetch aborts occur at the right place. */
861 } while (!dc
->is_jmp
&&
862 !tcg_op_buf_full() &&
863 num_insns
< max_insns
);
865 /* Indicate where the next block should start */
866 switch (dc
->is_jmp
) {
868 /* Save the current PC back into the CPU register */
869 tcg_gen_movi_tl(cpu_R
[R_PC
], dc
->pc
);
870 tcg_gen_exit_tb(NULL
, 0);
876 /* The jump will already have updated the PC register */
877 tcg_gen_exit_tb(NULL
, 0);
881 /* nothing more to generate */
885 /* End off the block */
886 gen_tb_end(tb
, num_insns
);
888 /* Mark instruction starts for the final generated instruction */
889 tb
->size
= dc
->pc
- tb
->pc
;
890 tb
->icount
= num_insns
;
893 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)
894 && qemu_log_in_addr_range(tb
->pc
)) {
895 FILE *logfile
= qemu_log_lock();
896 qemu_log("IN: %s\n", lookup_symbol(tb
->pc
));
897 log_target_disas(cs
, tb
->pc
, dc
->pc
- tb
->pc
);
899 qemu_log_unlock(logfile
);
904 void nios2_cpu_dump_state(CPUState
*cs
, FILE *f
, int flags
)
906 Nios2CPU
*cpu
= NIOS2_CPU(cs
);
907 CPUNios2State
*env
= &cpu
->env
;
914 qemu_fprintf(f
, "IN: PC=%x %s\n",
915 env
->regs
[R_PC
], lookup_symbol(env
->regs
[R_PC
]));
917 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
918 qemu_fprintf(f
, "%9s=%8.8x ", regnames
[i
], env
->regs
[i
]);
919 if ((i
+ 1) % 4 == 0) {
920 qemu_fprintf(f
, "\n");
923 #if !defined(CONFIG_USER_ONLY)
924 qemu_fprintf(f
, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
925 env
->mmu
.pteaddr_wr
& CR_PTEADDR_VPN_MASK
,
926 (env
->mmu
.tlbmisc_wr
& CR_TLBMISC_PID_MASK
) >> 4,
929 qemu_fprintf(f
, "\n\n");
932 void nios2_tcg_init(void)
936 for (i
= 0; i
< NUM_CORE_REGS
; i
++) {
937 cpu_R
[i
] = tcg_global_mem_new(cpu_env
,
938 offsetof(CPUNios2State
, regs
[i
]),
943 void restore_state_to_opc(CPUNios2State
*env
, TranslationBlock
*tb
,
946 env
->regs
[R_PC
] = data
[0];