xref: /qemu/target/openrisc/translate.c (revision b9bed1b9)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  * OpenRISC translation
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5fcf5ef2aSThomas Huth  *                         Feng Gao <gf91597@gmail.com>
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
10fcf5ef2aSThomas Huth  * version 2 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth  */
20fcf5ef2aSThomas Huth 
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "exec/exec-all.h"
24fcf5ef2aSThomas Huth #include "disas/disas.h"
25fcf5ef2aSThomas Huth #include "tcg-op.h"
26fcf5ef2aSThomas Huth #include "qemu-common.h"
27fcf5ef2aSThomas Huth #include "qemu/log.h"
28fcf5ef2aSThomas Huth #include "qemu/bitops.h"
29fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h"
3077fc6f5eSLluís Vilanova #include "exec/translator.h"
31fcf5ef2aSThomas Huth 
32fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
33fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
347de9729fSRichard Henderson #include "exec/gen-icount.h"
35fcf5ef2aSThomas Huth 
36fcf5ef2aSThomas Huth #include "trace-tcg.h"
37fcf5ef2aSThomas Huth #include "exec/log.h"
38fcf5ef2aSThomas Huth 
3977fc6f5eSLluís Vilanova /* is_jmp field values */
4064e46c95SRichard Henderson #define DISAS_EXIT    DISAS_TARGET_0  /* force exit to main loop */
418000ba56SRichard Henderson #define DISAS_JUMP    DISAS_TARGET_1  /* exit via jmp_pc/jmp_pc_imm */
4277fc6f5eSLluís Vilanova 
43fcf5ef2aSThomas Huth typedef struct DisasContext {
441ffa4bceSEmilio G. Cota     DisasContextBase base;
45fcf5ef2aSThomas Huth     uint32_t mem_idx;
46a01deb36SRichard Henderson     uint32_t tb_flags;
47fcf5ef2aSThomas Huth     uint32_t delayed_branch;
488000ba56SRichard Henderson 
498000ba56SRichard Henderson     /* If not -1, jmp_pc contains this value and so is a direct jump.  */
508000ba56SRichard Henderson     target_ulong jmp_pc_imm;
51fcf5ef2aSThomas Huth } DisasContext;
52fcf5ef2aSThomas Huth 
532ba65417SRichard Henderson static inline bool is_user(DisasContext *dc)
542ba65417SRichard Henderson {
552ba65417SRichard Henderson #ifdef CONFIG_USER_ONLY
562ba65417SRichard Henderson     return true;
572ba65417SRichard Henderson #else
58*b9bed1b9SRichard Henderson     return !(dc->tb_flags & TB_FLAGS_SM);
592ba65417SRichard Henderson #endif
602ba65417SRichard Henderson }
612ba65417SRichard Henderson 
627de9729fSRichard Henderson /* Include the auto-generated decoder.  */
637de9729fSRichard Henderson #include "decode.inc.c"
647de9729fSRichard Henderson 
65fcf5ef2aSThomas Huth static TCGv cpu_sr;
66fcf5ef2aSThomas Huth static TCGv cpu_R[32];
676597c28dSRichard Henderson static TCGv cpu_R0;
68fcf5ef2aSThomas Huth static TCGv cpu_pc;
69fcf5ef2aSThomas Huth static TCGv jmp_pc;            /* l.jr/l.jalr temp pc */
70fcf5ef2aSThomas Huth static TCGv cpu_ppc;
7184775c43SRichard Henderson static TCGv cpu_sr_f;           /* bf/bnf, F flag taken */
7297458071SRichard Henderson static TCGv cpu_sr_cy;          /* carry (unsigned overflow) */
7397458071SRichard Henderson static TCGv cpu_sr_ov;          /* signed overflow */
74930c3d00SRichard Henderson static TCGv cpu_lock_addr;
75930c3d00SRichard Henderson static TCGv cpu_lock_value;
76fcf5ef2aSThomas Huth static TCGv_i32 fpcsr;
776f7332baSRichard Henderson static TCGv_i64 cpu_mac;        /* MACHI:MACLO */
78a01deb36SRichard Henderson static TCGv_i32 cpu_dflag;
79fcf5ef2aSThomas Huth 
80fcf5ef2aSThomas Huth void openrisc_translate_init(void)
81fcf5ef2aSThomas Huth {
82fcf5ef2aSThomas Huth     static const char * const regnames[] = {
83fcf5ef2aSThomas Huth         "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
84fcf5ef2aSThomas Huth         "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
85fcf5ef2aSThomas Huth         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
86fcf5ef2aSThomas Huth         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
87fcf5ef2aSThomas Huth     };
88fcf5ef2aSThomas Huth     int i;
89fcf5ef2aSThomas Huth 
90fcf5ef2aSThomas Huth     cpu_sr = tcg_global_mem_new(cpu_env,
91fcf5ef2aSThomas Huth                                 offsetof(CPUOpenRISCState, sr), "sr");
92a01deb36SRichard Henderson     cpu_dflag = tcg_global_mem_new_i32(cpu_env,
93a01deb36SRichard Henderson                                        offsetof(CPUOpenRISCState, dflag),
94a01deb36SRichard Henderson                                        "dflag");
95fcf5ef2aSThomas Huth     cpu_pc = tcg_global_mem_new(cpu_env,
96fcf5ef2aSThomas Huth                                 offsetof(CPUOpenRISCState, pc), "pc");
97fcf5ef2aSThomas Huth     cpu_ppc = tcg_global_mem_new(cpu_env,
98fcf5ef2aSThomas Huth                                  offsetof(CPUOpenRISCState, ppc), "ppc");
99fcf5ef2aSThomas Huth     jmp_pc = tcg_global_mem_new(cpu_env,
100fcf5ef2aSThomas Huth                                 offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc");
10184775c43SRichard Henderson     cpu_sr_f = tcg_global_mem_new(cpu_env,
10284775c43SRichard Henderson                                   offsetof(CPUOpenRISCState, sr_f), "sr_f");
10397458071SRichard Henderson     cpu_sr_cy = tcg_global_mem_new(cpu_env,
10497458071SRichard Henderson                                    offsetof(CPUOpenRISCState, sr_cy), "sr_cy");
10597458071SRichard Henderson     cpu_sr_ov = tcg_global_mem_new(cpu_env,
10697458071SRichard Henderson                                    offsetof(CPUOpenRISCState, sr_ov), "sr_ov");
107930c3d00SRichard Henderson     cpu_lock_addr = tcg_global_mem_new(cpu_env,
108930c3d00SRichard Henderson                                        offsetof(CPUOpenRISCState, lock_addr),
109930c3d00SRichard Henderson                                        "lock_addr");
110930c3d00SRichard Henderson     cpu_lock_value = tcg_global_mem_new(cpu_env,
111930c3d00SRichard Henderson                                         offsetof(CPUOpenRISCState, lock_value),
112930c3d00SRichard Henderson                                         "lock_value");
113fcf5ef2aSThomas Huth     fpcsr = tcg_global_mem_new_i32(cpu_env,
114fcf5ef2aSThomas Huth                                    offsetof(CPUOpenRISCState, fpcsr),
115fcf5ef2aSThomas Huth                                    "fpcsr");
1166f7332baSRichard Henderson     cpu_mac = tcg_global_mem_new_i64(cpu_env,
1176f7332baSRichard Henderson                                      offsetof(CPUOpenRISCState, mac),
1186f7332baSRichard Henderson                                      "mac");
119fcf5ef2aSThomas Huth     for (i = 0; i < 32; i++) {
120fcf5ef2aSThomas Huth         cpu_R[i] = tcg_global_mem_new(cpu_env,
121d89e71e8SStafford Horne                                       offsetof(CPUOpenRISCState,
122d89e71e8SStafford Horne                                                shadow_gpr[0][i]),
123fcf5ef2aSThomas Huth                                       regnames[i]);
124fcf5ef2aSThomas Huth     }
1256597c28dSRichard Henderson     cpu_R0 = cpu_R[0];
126fcf5ef2aSThomas Huth }
127fcf5ef2aSThomas Huth 
128fcf5ef2aSThomas Huth static void gen_exception(DisasContext *dc, unsigned int excp)
129fcf5ef2aSThomas Huth {
130fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(excp);
131fcf5ef2aSThomas Huth     gen_helper_exception(cpu_env, tmp);
132fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
133fcf5ef2aSThomas Huth }
134fcf5ef2aSThomas Huth 
135fcf5ef2aSThomas Huth static void gen_illegal_exception(DisasContext *dc)
136fcf5ef2aSThomas Huth {
1371ffa4bceSEmilio G. Cota     tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
138fcf5ef2aSThomas Huth     gen_exception(dc, EXCP_ILLEGAL);
1391ffa4bceSEmilio G. Cota     dc->base.is_jmp = DISAS_NORETURN;
140fcf5ef2aSThomas Huth }
141fcf5ef2aSThomas Huth 
142fcf5ef2aSThomas Huth /* not used yet, open it when we need or64.  */
143fcf5ef2aSThomas Huth /*#ifdef TARGET_OPENRISC64
144fcf5ef2aSThomas Huth static void check_ob64s(DisasContext *dc)
145fcf5ef2aSThomas Huth {
146fcf5ef2aSThomas Huth     if (!(dc->flags & CPUCFGR_OB64S)) {
147fcf5ef2aSThomas Huth         gen_illegal_exception(dc);
148fcf5ef2aSThomas Huth     }
149fcf5ef2aSThomas Huth }
150fcf5ef2aSThomas Huth 
151fcf5ef2aSThomas Huth static void check_of64s(DisasContext *dc)
152fcf5ef2aSThomas Huth {
153fcf5ef2aSThomas Huth     if (!(dc->flags & CPUCFGR_OF64S)) {
154fcf5ef2aSThomas Huth         gen_illegal_exception(dc);
155fcf5ef2aSThomas Huth     }
156fcf5ef2aSThomas Huth }
157fcf5ef2aSThomas Huth 
158fcf5ef2aSThomas Huth static void check_ov64s(DisasContext *dc)
159fcf5ef2aSThomas Huth {
160fcf5ef2aSThomas Huth     if (!(dc->flags & CPUCFGR_OV64S)) {
161fcf5ef2aSThomas Huth         gen_illegal_exception(dc);
162fcf5ef2aSThomas Huth     }
163fcf5ef2aSThomas Huth }
164fcf5ef2aSThomas Huth #endif*/
165fcf5ef2aSThomas Huth 
1666597c28dSRichard Henderson /* We're about to write to REG.  On the off-chance that the user is
1676597c28dSRichard Henderson    writing to R0, re-instate the architectural register.  */
1686597c28dSRichard Henderson #define check_r0_write(reg)             \
1696597c28dSRichard Henderson     do {                                \
1706597c28dSRichard Henderson         if (unlikely(reg == 0)) {       \
1716597c28dSRichard Henderson             cpu_R[0] = cpu_R0;          \
1726597c28dSRichard Henderson         }                               \
1736597c28dSRichard Henderson     } while (0)
1746597c28dSRichard Henderson 
17597458071SRichard Henderson static void gen_ove_cy(DisasContext *dc)
1769ecaa27eSRichard Henderson {
1770c53d734SRichard Henderson     if (dc->tb_flags & SR_OVE) {
17897458071SRichard Henderson         gen_helper_ove_cy(cpu_env);
1799ecaa27eSRichard Henderson     }
1800c53d734SRichard Henderson }
1819ecaa27eSRichard Henderson 
18297458071SRichard Henderson static void gen_ove_ov(DisasContext *dc)
1839ecaa27eSRichard Henderson {
1840c53d734SRichard Henderson     if (dc->tb_flags & SR_OVE) {
18597458071SRichard Henderson         gen_helper_ove_ov(cpu_env);
1869ecaa27eSRichard Henderson     }
1870c53d734SRichard Henderson }
1889ecaa27eSRichard Henderson 
18997458071SRichard Henderson static void gen_ove_cyov(DisasContext *dc)
1909ecaa27eSRichard Henderson {
1910c53d734SRichard Henderson     if (dc->tb_flags & SR_OVE) {
19297458071SRichard Henderson         gen_helper_ove_cyov(cpu_env);
1939ecaa27eSRichard Henderson     }
1940c53d734SRichard Henderson }
1959ecaa27eSRichard Henderson 
1969ecaa27eSRichard Henderson static void gen_add(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb)
1979ecaa27eSRichard Henderson {
1989ecaa27eSRichard Henderson     TCGv t0 = tcg_const_tl(0);
1999ecaa27eSRichard Henderson     TCGv res = tcg_temp_new();
2009ecaa27eSRichard Henderson 
20197458071SRichard Henderson     tcg_gen_add2_tl(res, cpu_sr_cy, srca, t0, srcb, t0);
20297458071SRichard Henderson     tcg_gen_xor_tl(cpu_sr_ov, srca, srcb);
2039ecaa27eSRichard Henderson     tcg_gen_xor_tl(t0, res, srcb);
20497458071SRichard Henderson     tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov);
2059ecaa27eSRichard Henderson     tcg_temp_free(t0);
2069ecaa27eSRichard Henderson 
2079ecaa27eSRichard Henderson     tcg_gen_mov_tl(dest, res);
2089ecaa27eSRichard Henderson     tcg_temp_free(res);
2099ecaa27eSRichard Henderson 
21097458071SRichard Henderson     gen_ove_cyov(dc);
2119ecaa27eSRichard Henderson }
2129ecaa27eSRichard Henderson 
2139ecaa27eSRichard Henderson static void gen_addc(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb)
2149ecaa27eSRichard Henderson {
2159ecaa27eSRichard Henderson     TCGv t0 = tcg_const_tl(0);
2169ecaa27eSRichard Henderson     TCGv res = tcg_temp_new();
2179ecaa27eSRichard Henderson 
21897458071SRichard Henderson     tcg_gen_add2_tl(res, cpu_sr_cy, srca, t0, cpu_sr_cy, t0);
21997458071SRichard Henderson     tcg_gen_add2_tl(res, cpu_sr_cy, res, cpu_sr_cy, srcb, t0);
22097458071SRichard Henderson     tcg_gen_xor_tl(cpu_sr_ov, srca, srcb);
2219ecaa27eSRichard Henderson     tcg_gen_xor_tl(t0, res, srcb);
22297458071SRichard Henderson     tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov);
2239ecaa27eSRichard Henderson     tcg_temp_free(t0);
2249ecaa27eSRichard Henderson 
2259ecaa27eSRichard Henderson     tcg_gen_mov_tl(dest, res);
2269ecaa27eSRichard Henderson     tcg_temp_free(res);
2279ecaa27eSRichard Henderson 
22897458071SRichard Henderson     gen_ove_cyov(dc);
2299ecaa27eSRichard Henderson }
2309ecaa27eSRichard Henderson 
2319ecaa27eSRichard Henderson static void gen_sub(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb)
2329ecaa27eSRichard Henderson {
2339ecaa27eSRichard Henderson     TCGv res = tcg_temp_new();
2349ecaa27eSRichard Henderson 
2359ecaa27eSRichard Henderson     tcg_gen_sub_tl(res, srca, srcb);
23697458071SRichard Henderson     tcg_gen_xor_tl(cpu_sr_cy, srca, srcb);
23797458071SRichard Henderson     tcg_gen_xor_tl(cpu_sr_ov, res, srcb);
23897458071SRichard Henderson     tcg_gen_and_tl(cpu_sr_ov, cpu_sr_ov, cpu_sr_cy);
23997458071SRichard Henderson     tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_cy, srca, srcb);
2409ecaa27eSRichard Henderson 
2419ecaa27eSRichard Henderson     tcg_gen_mov_tl(dest, res);
2429ecaa27eSRichard Henderson     tcg_temp_free(res);
2439ecaa27eSRichard Henderson 
24497458071SRichard Henderson     gen_ove_cyov(dc);
2459ecaa27eSRichard Henderson }
2469ecaa27eSRichard Henderson 
2479ecaa27eSRichard Henderson static void gen_mul(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb)
2489ecaa27eSRichard Henderson {
2499ecaa27eSRichard Henderson     TCGv t0 = tcg_temp_new();
2509ecaa27eSRichard Henderson 
25197458071SRichard Henderson     tcg_gen_muls2_tl(dest, cpu_sr_ov, srca, srcb);
2529ecaa27eSRichard Henderson     tcg_gen_sari_tl(t0, dest, TARGET_LONG_BITS - 1);
25397458071SRichard Henderson     tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_ov, cpu_sr_ov, t0);
2549ecaa27eSRichard Henderson     tcg_temp_free(t0);
2559ecaa27eSRichard Henderson 
25697458071SRichard Henderson     tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov);
25797458071SRichard Henderson     gen_ove_ov(dc);
2589ecaa27eSRichard Henderson }
2599ecaa27eSRichard Henderson 
2609ecaa27eSRichard Henderson static void gen_mulu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb)
2619ecaa27eSRichard Henderson {
26297458071SRichard Henderson     tcg_gen_muls2_tl(dest, cpu_sr_cy, srca, srcb);
26397458071SRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_cy, cpu_sr_cy, 0);
2649ecaa27eSRichard Henderson 
26597458071SRichard Henderson     gen_ove_cy(dc);
2669ecaa27eSRichard Henderson }
2679ecaa27eSRichard Henderson 
2689ecaa27eSRichard Henderson static void gen_div(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb)
2699ecaa27eSRichard Henderson {
2709ecaa27eSRichard Henderson     TCGv t0 = tcg_temp_new();
2719ecaa27eSRichard Henderson 
27297458071SRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_ov, srcb, 0);
2739ecaa27eSRichard Henderson     /* The result of divide-by-zero is undefined.
2749ecaa27eSRichard Henderson        Supress the host-side exception by dividing by 1.  */
27597458071SRichard Henderson     tcg_gen_or_tl(t0, srcb, cpu_sr_ov);
2769ecaa27eSRichard Henderson     tcg_gen_div_tl(dest, srca, t0);
2779ecaa27eSRichard Henderson     tcg_temp_free(t0);
2789ecaa27eSRichard Henderson 
27997458071SRichard Henderson     tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov);
28097458071SRichard Henderson     gen_ove_ov(dc);
2819ecaa27eSRichard Henderson }
2829ecaa27eSRichard Henderson 
2839ecaa27eSRichard Henderson static void gen_divu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb)
2849ecaa27eSRichard Henderson {
2859ecaa27eSRichard Henderson     TCGv t0 = tcg_temp_new();
2869ecaa27eSRichard Henderson 
28797458071SRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_cy, srcb, 0);
2889ecaa27eSRichard Henderson     /* The result of divide-by-zero is undefined.
2899ecaa27eSRichard Henderson        Supress the host-side exception by dividing by 1.  */
29097458071SRichard Henderson     tcg_gen_or_tl(t0, srcb, cpu_sr_cy);
2919ecaa27eSRichard Henderson     tcg_gen_divu_tl(dest, srca, t0);
2929ecaa27eSRichard Henderson     tcg_temp_free(t0);
2939ecaa27eSRichard Henderson 
29497458071SRichard Henderson     gen_ove_cy(dc);
2959ecaa27eSRichard Henderson }
296fcf5ef2aSThomas Huth 
297cc5de49eSRichard Henderson static void gen_muld(DisasContext *dc, TCGv srca, TCGv srcb)
298cc5de49eSRichard Henderson {
299cc5de49eSRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
300cc5de49eSRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
301cc5de49eSRichard Henderson 
302cc5de49eSRichard Henderson     tcg_gen_ext_tl_i64(t1, srca);
303cc5de49eSRichard Henderson     tcg_gen_ext_tl_i64(t2, srcb);
304cc5de49eSRichard Henderson     if (TARGET_LONG_BITS == 32) {
305cc5de49eSRichard Henderson         tcg_gen_mul_i64(cpu_mac, t1, t2);
306cc5de49eSRichard Henderson         tcg_gen_movi_tl(cpu_sr_ov, 0);
307cc5de49eSRichard Henderson     } else {
308cc5de49eSRichard Henderson         TCGv_i64 high = tcg_temp_new_i64();
309cc5de49eSRichard Henderson 
310cc5de49eSRichard Henderson         tcg_gen_muls2_i64(cpu_mac, high, t1, t2);
311cc5de49eSRichard Henderson         tcg_gen_sari_i64(t1, cpu_mac, 63);
312cc5de49eSRichard Henderson         tcg_gen_setcond_i64(TCG_COND_NE, t1, t1, high);
313cc5de49eSRichard Henderson         tcg_temp_free_i64(high);
314cc5de49eSRichard Henderson         tcg_gen_trunc_i64_tl(cpu_sr_ov, t1);
315cc5de49eSRichard Henderson         tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov);
316cc5de49eSRichard Henderson 
317cc5de49eSRichard Henderson         gen_ove_ov(dc);
318cc5de49eSRichard Henderson     }
319cc5de49eSRichard Henderson     tcg_temp_free_i64(t1);
320cc5de49eSRichard Henderson     tcg_temp_free_i64(t2);
321cc5de49eSRichard Henderson }
322cc5de49eSRichard Henderson 
323cc5de49eSRichard Henderson static void gen_muldu(DisasContext *dc, TCGv srca, TCGv srcb)
324cc5de49eSRichard Henderson {
325cc5de49eSRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
326cc5de49eSRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
327cc5de49eSRichard Henderson 
328cc5de49eSRichard Henderson     tcg_gen_extu_tl_i64(t1, srca);
329cc5de49eSRichard Henderson     tcg_gen_extu_tl_i64(t2, srcb);
330cc5de49eSRichard Henderson     if (TARGET_LONG_BITS == 32) {
331cc5de49eSRichard Henderson         tcg_gen_mul_i64(cpu_mac, t1, t2);
332cc5de49eSRichard Henderson         tcg_gen_movi_tl(cpu_sr_cy, 0);
333cc5de49eSRichard Henderson     } else {
334cc5de49eSRichard Henderson         TCGv_i64 high = tcg_temp_new_i64();
335cc5de49eSRichard Henderson 
336cc5de49eSRichard Henderson         tcg_gen_mulu2_i64(cpu_mac, high, t1, t2);
337cc5de49eSRichard Henderson         tcg_gen_setcondi_i64(TCG_COND_NE, high, high, 0);
338cc5de49eSRichard Henderson         tcg_gen_trunc_i64_tl(cpu_sr_cy, high);
339cc5de49eSRichard Henderson         tcg_temp_free_i64(high);
340cc5de49eSRichard Henderson 
341cc5de49eSRichard Henderson         gen_ove_cy(dc);
342cc5de49eSRichard Henderson     }
343cc5de49eSRichard Henderson     tcg_temp_free_i64(t1);
344cc5de49eSRichard Henderson     tcg_temp_free_i64(t2);
345cc5de49eSRichard Henderson }
346cc5de49eSRichard Henderson 
3476f7332baSRichard Henderson static void gen_mac(DisasContext *dc, TCGv srca, TCGv srcb)
3486f7332baSRichard Henderson {
3496f7332baSRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
3506f7332baSRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
3516f7332baSRichard Henderson 
3526f7332baSRichard Henderson     tcg_gen_ext_tl_i64(t1, srca);
3536f7332baSRichard Henderson     tcg_gen_ext_tl_i64(t2, srcb);
3546f7332baSRichard Henderson     tcg_gen_mul_i64(t1, t1, t2);
3556f7332baSRichard Henderson 
3566f7332baSRichard Henderson     /* Note that overflow is only computed during addition stage.  */
3576f7332baSRichard Henderson     tcg_gen_xor_i64(t2, cpu_mac, t1);
3586f7332baSRichard Henderson     tcg_gen_add_i64(cpu_mac, cpu_mac, t1);
3596f7332baSRichard Henderson     tcg_gen_xor_i64(t1, t1, cpu_mac);
3606f7332baSRichard Henderson     tcg_gen_andc_i64(t1, t1, t2);
3616f7332baSRichard Henderson     tcg_temp_free_i64(t2);
3626f7332baSRichard Henderson 
3636f7332baSRichard Henderson #if TARGET_LONG_BITS == 32
3646f7332baSRichard Henderson     tcg_gen_extrh_i64_i32(cpu_sr_ov, t1);
3656f7332baSRichard Henderson #else
3666f7332baSRichard Henderson     tcg_gen_mov_i64(cpu_sr_ov, t1);
3676f7332baSRichard Henderson #endif
3686f7332baSRichard Henderson     tcg_temp_free_i64(t1);
3696f7332baSRichard Henderson 
3706f7332baSRichard Henderson     gen_ove_ov(dc);
3716f7332baSRichard Henderson }
3726f7332baSRichard Henderson 
373cc5de49eSRichard Henderson static void gen_macu(DisasContext *dc, TCGv srca, TCGv srcb)
374cc5de49eSRichard Henderson {
375cc5de49eSRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
376cc5de49eSRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
377cc5de49eSRichard Henderson 
378cc5de49eSRichard Henderson     tcg_gen_extu_tl_i64(t1, srca);
379cc5de49eSRichard Henderson     tcg_gen_extu_tl_i64(t2, srcb);
380cc5de49eSRichard Henderson     tcg_gen_mul_i64(t1, t1, t2);
381cc5de49eSRichard Henderson     tcg_temp_free_i64(t2);
382cc5de49eSRichard Henderson 
383cc5de49eSRichard Henderson     /* Note that overflow is only computed during addition stage.  */
384cc5de49eSRichard Henderson     tcg_gen_add_i64(cpu_mac, cpu_mac, t1);
385cc5de49eSRichard Henderson     tcg_gen_setcond_i64(TCG_COND_LTU, t1, cpu_mac, t1);
386cc5de49eSRichard Henderson     tcg_gen_trunc_i64_tl(cpu_sr_cy, t1);
387cc5de49eSRichard Henderson     tcg_temp_free_i64(t1);
388cc5de49eSRichard Henderson 
389cc5de49eSRichard Henderson     gen_ove_cy(dc);
390cc5de49eSRichard Henderson }
391cc5de49eSRichard Henderson 
3926f7332baSRichard Henderson static void gen_msb(DisasContext *dc, TCGv srca, TCGv srcb)
3936f7332baSRichard Henderson {
3946f7332baSRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
3956f7332baSRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
3966f7332baSRichard Henderson 
3976f7332baSRichard Henderson     tcg_gen_ext_tl_i64(t1, srca);
3986f7332baSRichard Henderson     tcg_gen_ext_tl_i64(t2, srcb);
3996f7332baSRichard Henderson     tcg_gen_mul_i64(t1, t1, t2);
4006f7332baSRichard Henderson 
4016f7332baSRichard Henderson     /* Note that overflow is only computed during subtraction stage.  */
4026f7332baSRichard Henderson     tcg_gen_xor_i64(t2, cpu_mac, t1);
4036f7332baSRichard Henderson     tcg_gen_sub_i64(cpu_mac, cpu_mac, t1);
4046f7332baSRichard Henderson     tcg_gen_xor_i64(t1, t1, cpu_mac);
4056f7332baSRichard Henderson     tcg_gen_and_i64(t1, t1, t2);
4066f7332baSRichard Henderson     tcg_temp_free_i64(t2);
4076f7332baSRichard Henderson 
4086f7332baSRichard Henderson #if TARGET_LONG_BITS == 32
4096f7332baSRichard Henderson     tcg_gen_extrh_i64_i32(cpu_sr_ov, t1);
4106f7332baSRichard Henderson #else
4116f7332baSRichard Henderson     tcg_gen_mov_i64(cpu_sr_ov, t1);
4126f7332baSRichard Henderson #endif
4136f7332baSRichard Henderson     tcg_temp_free_i64(t1);
4146f7332baSRichard Henderson 
4156f7332baSRichard Henderson     gen_ove_ov(dc);
4166f7332baSRichard Henderson }
4176f7332baSRichard Henderson 
418cc5de49eSRichard Henderson static void gen_msbu(DisasContext *dc, TCGv srca, TCGv srcb)
419cc5de49eSRichard Henderson {
420cc5de49eSRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
421cc5de49eSRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
422cc5de49eSRichard Henderson 
423cc5de49eSRichard Henderson     tcg_gen_extu_tl_i64(t1, srca);
424cc5de49eSRichard Henderson     tcg_gen_extu_tl_i64(t2, srcb);
425cc5de49eSRichard Henderson     tcg_gen_mul_i64(t1, t1, t2);
426cc5de49eSRichard Henderson 
427cc5de49eSRichard Henderson     /* Note that overflow is only computed during subtraction stage.  */
428cc5de49eSRichard Henderson     tcg_gen_setcond_i64(TCG_COND_LTU, t2, cpu_mac, t1);
429cc5de49eSRichard Henderson     tcg_gen_sub_i64(cpu_mac, cpu_mac, t1);
430cc5de49eSRichard Henderson     tcg_gen_trunc_i64_tl(cpu_sr_cy, t2);
431cc5de49eSRichard Henderson     tcg_temp_free_i64(t2);
432cc5de49eSRichard Henderson     tcg_temp_free_i64(t1);
433cc5de49eSRichard Henderson 
434cc5de49eSRichard Henderson     gen_ove_cy(dc);
435cc5de49eSRichard Henderson }
436cc5de49eSRichard Henderson 
4376ad216abSRichard Henderson static bool trans_l_add(DisasContext *dc, arg_dab *a, uint32_t insn)
438fcf5ef2aSThomas Huth {
4396ad216abSRichard Henderson     check_r0_write(a->d);
4406ad216abSRichard Henderson     gen_add(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4416ad216abSRichard Henderson     return true;
442fcf5ef2aSThomas Huth }
443fcf5ef2aSThomas Huth 
4446ad216abSRichard Henderson static bool trans_l_addc(DisasContext *dc, arg_dab *a, uint32_t insn)
445fcf5ef2aSThomas Huth {
4466ad216abSRichard Henderson     check_r0_write(a->d);
4476ad216abSRichard Henderson     gen_addc(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4486ad216abSRichard Henderson     return true;
4496ad216abSRichard Henderson }
4506ad216abSRichard Henderson 
4516ad216abSRichard Henderson static bool trans_l_sub(DisasContext *dc, arg_dab *a, uint32_t insn)
4526ad216abSRichard Henderson {
4536ad216abSRichard Henderson     check_r0_write(a->d);
4546ad216abSRichard Henderson     gen_sub(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4556ad216abSRichard Henderson     return true;
4566ad216abSRichard Henderson }
4576ad216abSRichard Henderson 
4586ad216abSRichard Henderson static bool trans_l_and(DisasContext *dc, arg_dab *a, uint32_t insn)
4596ad216abSRichard Henderson {
4606ad216abSRichard Henderson     check_r0_write(a->d);
4616ad216abSRichard Henderson     tcg_gen_and_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4626ad216abSRichard Henderson     return true;
4636ad216abSRichard Henderson }
4646ad216abSRichard Henderson 
4656ad216abSRichard Henderson static bool trans_l_or(DisasContext *dc, arg_dab *a, uint32_t insn)
4666ad216abSRichard Henderson {
4676ad216abSRichard Henderson     check_r0_write(a->d);
4686ad216abSRichard Henderson     tcg_gen_or_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4696ad216abSRichard Henderson     return true;
4706ad216abSRichard Henderson }
4716ad216abSRichard Henderson 
4726ad216abSRichard Henderson static bool trans_l_xor(DisasContext *dc, arg_dab *a, uint32_t insn)
4736ad216abSRichard Henderson {
4746ad216abSRichard Henderson     check_r0_write(a->d);
4756ad216abSRichard Henderson     tcg_gen_xor_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4766ad216abSRichard Henderson     return true;
4776ad216abSRichard Henderson }
4786ad216abSRichard Henderson 
4796ad216abSRichard Henderson static bool trans_l_sll(DisasContext *dc, arg_dab *a, uint32_t insn)
4806ad216abSRichard Henderson {
4816ad216abSRichard Henderson     check_r0_write(a->d);
4826ad216abSRichard Henderson     tcg_gen_shl_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4836ad216abSRichard Henderson     return true;
4846ad216abSRichard Henderson }
4856ad216abSRichard Henderson 
4866ad216abSRichard Henderson static bool trans_l_srl(DisasContext *dc, arg_dab *a, uint32_t insn)
4876ad216abSRichard Henderson {
4886ad216abSRichard Henderson     check_r0_write(a->d);
4896ad216abSRichard Henderson     tcg_gen_shr_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4906ad216abSRichard Henderson     return true;
4916ad216abSRichard Henderson }
4926ad216abSRichard Henderson 
4936ad216abSRichard Henderson static bool trans_l_sra(DisasContext *dc, arg_dab *a, uint32_t insn)
4946ad216abSRichard Henderson {
4956ad216abSRichard Henderson     check_r0_write(a->d);
4966ad216abSRichard Henderson     tcg_gen_sar_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
4976ad216abSRichard Henderson     return true;
4986ad216abSRichard Henderson }
4996ad216abSRichard Henderson 
5006ad216abSRichard Henderson static bool trans_l_ror(DisasContext *dc, arg_dab *a, uint32_t insn)
5016ad216abSRichard Henderson {
5026ad216abSRichard Henderson     check_r0_write(a->d);
5036ad216abSRichard Henderson     tcg_gen_rotr_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
5046ad216abSRichard Henderson     return true;
5056ad216abSRichard Henderson }
5066ad216abSRichard Henderson 
5076ad216abSRichard Henderson static bool trans_l_exths(DisasContext *dc, arg_da *a, uint32_t insn)
5086ad216abSRichard Henderson {
5096ad216abSRichard Henderson     check_r0_write(a->d);
5106ad216abSRichard Henderson     tcg_gen_ext16s_tl(cpu_R[a->d], cpu_R[a->a]);
5116ad216abSRichard Henderson     return true;
5126ad216abSRichard Henderson }
5136ad216abSRichard Henderson 
5146ad216abSRichard Henderson static bool trans_l_extbs(DisasContext *dc, arg_da *a, uint32_t insn)
5156ad216abSRichard Henderson {
5166ad216abSRichard Henderson     check_r0_write(a->d);
5176ad216abSRichard Henderson     tcg_gen_ext8s_tl(cpu_R[a->d], cpu_R[a->a]);
5186ad216abSRichard Henderson     return true;
5196ad216abSRichard Henderson }
5206ad216abSRichard Henderson 
5216ad216abSRichard Henderson static bool trans_l_exthz(DisasContext *dc, arg_da *a, uint32_t insn)
5226ad216abSRichard Henderson {
5236ad216abSRichard Henderson     check_r0_write(a->d);
5246ad216abSRichard Henderson     tcg_gen_ext16u_tl(cpu_R[a->d], cpu_R[a->a]);
5256ad216abSRichard Henderson     return true;
5266ad216abSRichard Henderson }
5276ad216abSRichard Henderson 
5286ad216abSRichard Henderson static bool trans_l_extbz(DisasContext *dc, arg_da *a, uint32_t insn)
5296ad216abSRichard Henderson {
5306ad216abSRichard Henderson     check_r0_write(a->d);
5316ad216abSRichard Henderson     tcg_gen_ext8u_tl(cpu_R[a->d], cpu_R[a->a]);
5326ad216abSRichard Henderson     return true;
5336ad216abSRichard Henderson }
5346ad216abSRichard Henderson 
5356ad216abSRichard Henderson static bool trans_l_cmov(DisasContext *dc, arg_dab *a, uint32_t insn)
5366ad216abSRichard Henderson {
5376ad216abSRichard Henderson     TCGv zero;
5386ad216abSRichard Henderson 
5396ad216abSRichard Henderson     check_r0_write(a->d);
5406ad216abSRichard Henderson     zero = tcg_const_tl(0);
5416ad216abSRichard Henderson     tcg_gen_movcond_tl(TCG_COND_NE, cpu_R[a->d], cpu_sr_f, zero,
5426ad216abSRichard Henderson                        cpu_R[a->a], cpu_R[a->b]);
543784696d1SRichard Henderson     tcg_temp_free(zero);
5446ad216abSRichard Henderson     return true;
545fcf5ef2aSThomas Huth }
546fcf5ef2aSThomas Huth 
5476ad216abSRichard Henderson static bool trans_l_ff1(DisasContext *dc, arg_da *a, uint32_t insn)
5486ad216abSRichard Henderson {
5496ad216abSRichard Henderson     check_r0_write(a->d);
5506ad216abSRichard Henderson     tcg_gen_ctzi_tl(cpu_R[a->d], cpu_R[a->a], -1);
5516ad216abSRichard Henderson     tcg_gen_addi_tl(cpu_R[a->d], cpu_R[a->d], 1);
5526ad216abSRichard Henderson     return true;
553cf2ae442SRichard Henderson }
554cf2ae442SRichard Henderson 
5556ad216abSRichard Henderson static bool trans_l_fl1(DisasContext *dc, arg_da *a, uint32_t insn)
5566ad216abSRichard Henderson {
5576ad216abSRichard Henderson     check_r0_write(a->d);
5586ad216abSRichard Henderson     tcg_gen_clzi_tl(cpu_R[a->d], cpu_R[a->a], TARGET_LONG_BITS);
5596ad216abSRichard Henderson     tcg_gen_subfi_tl(cpu_R[a->d], TARGET_LONG_BITS, cpu_R[a->d]);
5606ad216abSRichard Henderson     return true;
561fcf5ef2aSThomas Huth }
562fcf5ef2aSThomas Huth 
5636ad216abSRichard Henderson static bool trans_l_mul(DisasContext *dc, arg_dab *a, uint32_t insn)
5646ad216abSRichard Henderson {
5656ad216abSRichard Henderson     check_r0_write(a->d);
5666ad216abSRichard Henderson     gen_mul(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
5676ad216abSRichard Henderson     return true;
568fcf5ef2aSThomas Huth }
5696ad216abSRichard Henderson 
5706ad216abSRichard Henderson static bool trans_l_mulu(DisasContext *dc, arg_dab *a, uint32_t insn)
5716ad216abSRichard Henderson {
5726ad216abSRichard Henderson     check_r0_write(a->d);
5736ad216abSRichard Henderson     gen_mulu(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
5746ad216abSRichard Henderson     return true;
575fcf5ef2aSThomas Huth }
5766ad216abSRichard Henderson 
5776ad216abSRichard Henderson static bool trans_l_div(DisasContext *dc, arg_dab *a, uint32_t insn)
5786ad216abSRichard Henderson {
5796ad216abSRichard Henderson     check_r0_write(a->d);
5806ad216abSRichard Henderson     gen_div(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
5816ad216abSRichard Henderson     return true;
5826ad216abSRichard Henderson }
5836ad216abSRichard Henderson 
5846ad216abSRichard Henderson static bool trans_l_divu(DisasContext *dc, arg_dab *a, uint32_t insn)
5856ad216abSRichard Henderson {
5866ad216abSRichard Henderson     check_r0_write(a->d);
5876ad216abSRichard Henderson     gen_divu(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
5886ad216abSRichard Henderson     return true;
5896ad216abSRichard Henderson }
5906ad216abSRichard Henderson 
5916ad216abSRichard Henderson static bool trans_l_muld(DisasContext *dc, arg_ab *a, uint32_t insn)
5926ad216abSRichard Henderson {
5936ad216abSRichard Henderson     gen_muld(dc, cpu_R[a->a], cpu_R[a->b]);
5946ad216abSRichard Henderson     return true;
5956ad216abSRichard Henderson }
5966ad216abSRichard Henderson 
5976ad216abSRichard Henderson static bool trans_l_muldu(DisasContext *dc, arg_ab *a, uint32_t insn)
5986ad216abSRichard Henderson {
5996ad216abSRichard Henderson     gen_muldu(dc, cpu_R[a->a], cpu_R[a->b]);
6006ad216abSRichard Henderson     return true;
601fcf5ef2aSThomas Huth }
602fcf5ef2aSThomas Huth 
603136e13aeSRichard Henderson static bool trans_l_j(DisasContext *dc, arg_l_j *a, uint32_t insn)
604136e13aeSRichard Henderson {
605136e13aeSRichard Henderson     target_ulong tmp_pc = dc->base.pc_next + a->n * 4;
606136e13aeSRichard Henderson 
607136e13aeSRichard Henderson     tcg_gen_movi_tl(jmp_pc, tmp_pc);
6088000ba56SRichard Henderson     dc->jmp_pc_imm = tmp_pc;
609136e13aeSRichard Henderson     dc->delayed_branch = 2;
610136e13aeSRichard Henderson     return true;
611136e13aeSRichard Henderson }
612136e13aeSRichard Henderson 
613136e13aeSRichard Henderson static bool trans_l_jal(DisasContext *dc, arg_l_jal *a, uint32_t insn)
614136e13aeSRichard Henderson {
615136e13aeSRichard Henderson     target_ulong tmp_pc = dc->base.pc_next + a->n * 4;
616136e13aeSRichard Henderson     target_ulong ret_pc = dc->base.pc_next + 8;
617136e13aeSRichard Henderson 
618136e13aeSRichard Henderson     tcg_gen_movi_tl(cpu_R[9], ret_pc);
619136e13aeSRichard Henderson     /* Optimize jal being used to load the PC for PIC.  */
620136e13aeSRichard Henderson     if (tmp_pc != ret_pc) {
621136e13aeSRichard Henderson         tcg_gen_movi_tl(jmp_pc, tmp_pc);
6228000ba56SRichard Henderson         dc->jmp_pc_imm = tmp_pc;
623136e13aeSRichard Henderson         dc->delayed_branch = 2;
624136e13aeSRichard Henderson     }
625136e13aeSRichard Henderson     return true;
626136e13aeSRichard Henderson }
627136e13aeSRichard Henderson 
628136e13aeSRichard Henderson static void do_bf(DisasContext *dc, arg_l_bf *a, TCGCond cond)
629136e13aeSRichard Henderson {
630136e13aeSRichard Henderson     target_ulong tmp_pc = dc->base.pc_next + a->n * 4;
631136e13aeSRichard Henderson     TCGv t_next = tcg_const_tl(dc->base.pc_next + 8);
632136e13aeSRichard Henderson     TCGv t_true = tcg_const_tl(tmp_pc);
633136e13aeSRichard Henderson     TCGv t_zero = tcg_const_tl(0);
634136e13aeSRichard Henderson 
635136e13aeSRichard Henderson     tcg_gen_movcond_tl(cond, jmp_pc, cpu_sr_f, t_zero, t_true, t_next);
636136e13aeSRichard Henderson 
637136e13aeSRichard Henderson     tcg_temp_free(t_next);
638136e13aeSRichard Henderson     tcg_temp_free(t_true);
639136e13aeSRichard Henderson     tcg_temp_free(t_zero);
640136e13aeSRichard Henderson     dc->delayed_branch = 2;
641136e13aeSRichard Henderson }
642136e13aeSRichard Henderson 
643136e13aeSRichard Henderson static bool trans_l_bf(DisasContext *dc, arg_l_bf *a, uint32_t insn)
644136e13aeSRichard Henderson {
645136e13aeSRichard Henderson     do_bf(dc, a, TCG_COND_NE);
646136e13aeSRichard Henderson     return true;
647136e13aeSRichard Henderson }
648136e13aeSRichard Henderson 
649136e13aeSRichard Henderson static bool trans_l_bnf(DisasContext *dc, arg_l_bf *a, uint32_t insn)
650136e13aeSRichard Henderson {
651136e13aeSRichard Henderson     do_bf(dc, a, TCG_COND_EQ);
652136e13aeSRichard Henderson     return true;
653136e13aeSRichard Henderson }
654136e13aeSRichard Henderson 
655136e13aeSRichard Henderson static bool trans_l_jr(DisasContext *dc, arg_l_jr *a, uint32_t insn)
656136e13aeSRichard Henderson {
657136e13aeSRichard Henderson     tcg_gen_mov_tl(jmp_pc, cpu_R[a->b]);
658136e13aeSRichard Henderson     dc->delayed_branch = 2;
659136e13aeSRichard Henderson     return true;
660136e13aeSRichard Henderson }
661136e13aeSRichard Henderson 
662136e13aeSRichard Henderson static bool trans_l_jalr(DisasContext *dc, arg_l_jalr *a, uint32_t insn)
663136e13aeSRichard Henderson {
664136e13aeSRichard Henderson     tcg_gen_mov_tl(jmp_pc, cpu_R[a->b]);
665136e13aeSRichard Henderson     tcg_gen_movi_tl(cpu_R[9], dc->base.pc_next + 8);
666136e13aeSRichard Henderson     dc->delayed_branch = 2;
667136e13aeSRichard Henderson     return true;
668136e13aeSRichard Henderson }
669136e13aeSRichard Henderson 
670d80bff19SRichard Henderson static bool trans_l_lwa(DisasContext *dc, arg_load *a, uint32_t insn)
671d80bff19SRichard Henderson {
672d80bff19SRichard Henderson     TCGv ea;
673d80bff19SRichard Henderson 
674d80bff19SRichard Henderson     check_r0_write(a->d);
675d80bff19SRichard Henderson     ea = tcg_temp_new();
676d80bff19SRichard Henderson     tcg_gen_addi_tl(ea, cpu_R[a->a], a->i);
677d80bff19SRichard Henderson     tcg_gen_qemu_ld_tl(cpu_R[a->d], ea, dc->mem_idx, MO_TEUL);
678d80bff19SRichard Henderson     tcg_gen_mov_tl(cpu_lock_addr, ea);
679d80bff19SRichard Henderson     tcg_gen_mov_tl(cpu_lock_value, cpu_R[a->d]);
680d80bff19SRichard Henderson     tcg_temp_free(ea);
681d80bff19SRichard Henderson     return true;
682d80bff19SRichard Henderson }
683d80bff19SRichard Henderson 
684d80bff19SRichard Henderson static void do_load(DisasContext *dc, arg_load *a, TCGMemOp mop)
685d80bff19SRichard Henderson {
686d80bff19SRichard Henderson     TCGv ea;
687d80bff19SRichard Henderson 
688d80bff19SRichard Henderson     check_r0_write(a->d);
689d80bff19SRichard Henderson     ea = tcg_temp_new();
690d80bff19SRichard Henderson     tcg_gen_addi_tl(ea, cpu_R[a->a], a->i);
691d80bff19SRichard Henderson     tcg_gen_qemu_ld_tl(cpu_R[a->d], ea, dc->mem_idx, mop);
692d80bff19SRichard Henderson     tcg_temp_free(ea);
693d80bff19SRichard Henderson }
694d80bff19SRichard Henderson 
695d80bff19SRichard Henderson static bool trans_l_lwz(DisasContext *dc, arg_load *a, uint32_t insn)
696d80bff19SRichard Henderson {
697d80bff19SRichard Henderson     do_load(dc, a, MO_TEUL);
698d80bff19SRichard Henderson     return true;
699d80bff19SRichard Henderson }
700d80bff19SRichard Henderson 
701d80bff19SRichard Henderson static bool trans_l_lws(DisasContext *dc, arg_load *a, uint32_t insn)
702d80bff19SRichard Henderson {
703d80bff19SRichard Henderson     do_load(dc, a, MO_TESL);
704d80bff19SRichard Henderson     return true;
705d80bff19SRichard Henderson }
706d80bff19SRichard Henderson 
707d80bff19SRichard Henderson static bool trans_l_lbz(DisasContext *dc, arg_load *a, uint32_t insn)
708d80bff19SRichard Henderson {
709d80bff19SRichard Henderson     do_load(dc, a, MO_UB);
710d80bff19SRichard Henderson     return true;
711d80bff19SRichard Henderson }
712d80bff19SRichard Henderson 
713d80bff19SRichard Henderson static bool trans_l_lbs(DisasContext *dc, arg_load *a, uint32_t insn)
714d80bff19SRichard Henderson {
715d80bff19SRichard Henderson     do_load(dc, a, MO_SB);
716d80bff19SRichard Henderson     return true;
717d80bff19SRichard Henderson }
718d80bff19SRichard Henderson 
719d80bff19SRichard Henderson static bool trans_l_lhz(DisasContext *dc, arg_load *a, uint32_t insn)
720d80bff19SRichard Henderson {
721d80bff19SRichard Henderson     do_load(dc, a, MO_TEUW);
722d80bff19SRichard Henderson     return true;
723d80bff19SRichard Henderson }
724d80bff19SRichard Henderson 
725d80bff19SRichard Henderson static bool trans_l_lhs(DisasContext *dc, arg_load *a, uint32_t insn)
726d80bff19SRichard Henderson {
727d80bff19SRichard Henderson     do_load(dc, a, MO_TESW);
728d80bff19SRichard Henderson     return true;
729d80bff19SRichard Henderson }
730d80bff19SRichard Henderson 
731d80bff19SRichard Henderson static bool trans_l_swa(DisasContext *dc, arg_store *a, uint32_t insn)
732d80bff19SRichard Henderson {
733d80bff19SRichard Henderson     TCGv ea, val;
734d80bff19SRichard Henderson     TCGLabel *lab_fail, *lab_done;
735d80bff19SRichard Henderson 
736d80bff19SRichard Henderson     ea = tcg_temp_new();
737d80bff19SRichard Henderson     tcg_gen_addi_tl(ea, cpu_R[a->a], a->i);
738d80bff19SRichard Henderson 
739d80bff19SRichard Henderson     /* For TB_FLAGS_R0_0, the branch below invalidates the temporary assigned
740d80bff19SRichard Henderson        to cpu_R[0].  Since l.swa is quite often immediately followed by a
741d80bff19SRichard Henderson        branch, don't bother reallocating; finish the TB using the "real" R0.
742d80bff19SRichard Henderson        This also takes care of RB input across the branch.  */
743d80bff19SRichard Henderson     cpu_R[0] = cpu_R0;
744d80bff19SRichard Henderson 
745d80bff19SRichard Henderson     lab_fail = gen_new_label();
746d80bff19SRichard Henderson     lab_done = gen_new_label();
747d80bff19SRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, ea, cpu_lock_addr, lab_fail);
748d80bff19SRichard Henderson     tcg_temp_free(ea);
749d80bff19SRichard Henderson 
750d80bff19SRichard Henderson     val = tcg_temp_new();
751d80bff19SRichard Henderson     tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value,
752d80bff19SRichard Henderson                               cpu_R[a->b], dc->mem_idx, MO_TEUL);
753d80bff19SRichard Henderson     tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, val, cpu_lock_value);
754d80bff19SRichard Henderson     tcg_temp_free(val);
755d80bff19SRichard Henderson 
756d80bff19SRichard Henderson     tcg_gen_br(lab_done);
757d80bff19SRichard Henderson 
758d80bff19SRichard Henderson     gen_set_label(lab_fail);
759d80bff19SRichard Henderson     tcg_gen_movi_tl(cpu_sr_f, 0);
760d80bff19SRichard Henderson 
761d80bff19SRichard Henderson     gen_set_label(lab_done);
762d80bff19SRichard Henderson     tcg_gen_movi_tl(cpu_lock_addr, -1);
763d80bff19SRichard Henderson     return true;
764d80bff19SRichard Henderson }
765d80bff19SRichard Henderson 
766d80bff19SRichard Henderson static void do_store(DisasContext *dc, arg_store *a, TCGMemOp mop)
767d80bff19SRichard Henderson {
768d80bff19SRichard Henderson     TCGv t0 = tcg_temp_new();
769d80bff19SRichard Henderson     tcg_gen_addi_tl(t0, cpu_R[a->a], a->i);
770d80bff19SRichard Henderson     tcg_gen_qemu_st_tl(cpu_R[a->b], t0, dc->mem_idx, mop);
771d80bff19SRichard Henderson     tcg_temp_free(t0);
772d80bff19SRichard Henderson }
773d80bff19SRichard Henderson 
774d80bff19SRichard Henderson static bool trans_l_sw(DisasContext *dc, arg_store *a, uint32_t insn)
775d80bff19SRichard Henderson {
776d80bff19SRichard Henderson     do_store(dc, a, MO_TEUL);
777d80bff19SRichard Henderson     return true;
778d80bff19SRichard Henderson }
779d80bff19SRichard Henderson 
780d80bff19SRichard Henderson static bool trans_l_sb(DisasContext *dc, arg_store *a, uint32_t insn)
781d80bff19SRichard Henderson {
782d80bff19SRichard Henderson     do_store(dc, a, MO_UB);
783d80bff19SRichard Henderson     return true;
784d80bff19SRichard Henderson }
785d80bff19SRichard Henderson 
786d80bff19SRichard Henderson static bool trans_l_sh(DisasContext *dc, arg_store *a, uint32_t insn)
787d80bff19SRichard Henderson {
788d80bff19SRichard Henderson     do_store(dc, a, MO_TEUW);
789d80bff19SRichard Henderson     return true;
790d80bff19SRichard Henderson }
791d80bff19SRichard Henderson 
7928816f70bSRichard Henderson static bool trans_l_nop(DisasContext *dc, arg_l_nop *a, uint32_t insn)
793fcf5ef2aSThomas Huth {
7948816f70bSRichard Henderson     return true;
7958816f70bSRichard Henderson }
7968816f70bSRichard Henderson 
7978816f70bSRichard Henderson static bool trans_l_addi(DisasContext *dc, arg_rri *a, uint32_t insn)
7988816f70bSRichard Henderson {
7999ecaa27eSRichard Henderson     TCGv t0;
800fcf5ef2aSThomas Huth 
8018816f70bSRichard Henderson     check_r0_write(a->d);
8028816f70bSRichard Henderson     t0 = tcg_const_tl(a->i);
8038816f70bSRichard Henderson     gen_add(dc, cpu_R[a->d], cpu_R[a->a], t0);
8046f7332baSRichard Henderson     tcg_temp_free(t0);
8058816f70bSRichard Henderson     return true;
8068816f70bSRichard Henderson }
807fcf5ef2aSThomas Huth 
8088816f70bSRichard Henderson static bool trans_l_addic(DisasContext *dc, arg_rri *a, uint32_t insn)
809fcf5ef2aSThomas Huth {
8108816f70bSRichard Henderson     TCGv t0;
8118816f70bSRichard Henderson 
8128816f70bSRichard Henderson     check_r0_write(a->d);
8138816f70bSRichard Henderson     t0 = tcg_const_tl(a->i);
8148816f70bSRichard Henderson     gen_addc(dc, cpu_R[a->d], cpu_R[a->a], t0);
8158816f70bSRichard Henderson     tcg_temp_free(t0);
8168816f70bSRichard Henderson     return true;
8178816f70bSRichard Henderson }
8188816f70bSRichard Henderson 
8198816f70bSRichard Henderson static bool trans_l_muli(DisasContext *dc, arg_rri *a, uint32_t insn)
8208816f70bSRichard Henderson {
8218816f70bSRichard Henderson     TCGv t0;
8228816f70bSRichard Henderson 
8238816f70bSRichard Henderson     check_r0_write(a->d);
8248816f70bSRichard Henderson     t0 = tcg_const_tl(a->i);
8258816f70bSRichard Henderson     gen_mul(dc, cpu_R[a->d], cpu_R[a->a], t0);
8268816f70bSRichard Henderson     tcg_temp_free(t0);
8278816f70bSRichard Henderson     return true;
8288816f70bSRichard Henderson }
8298816f70bSRichard Henderson 
8308816f70bSRichard Henderson static bool trans_l_maci(DisasContext *dc, arg_l_maci *a, uint32_t insn)
8318816f70bSRichard Henderson {
8328816f70bSRichard Henderson     TCGv t0;
8338816f70bSRichard Henderson 
8348816f70bSRichard Henderson     t0 = tcg_const_tl(a->i);
8358816f70bSRichard Henderson     gen_mac(dc, cpu_R[a->a], t0);
8368816f70bSRichard Henderson     tcg_temp_free(t0);
8378816f70bSRichard Henderson     return true;
8388816f70bSRichard Henderson }
8398816f70bSRichard Henderson 
8408816f70bSRichard Henderson static bool trans_l_andi(DisasContext *dc, arg_rrk *a, uint32_t insn)
8418816f70bSRichard Henderson {
8428816f70bSRichard Henderson     check_r0_write(a->d);
8438816f70bSRichard Henderson     tcg_gen_andi_tl(cpu_R[a->d], cpu_R[a->a], a->k);
8448816f70bSRichard Henderson     return true;
8458816f70bSRichard Henderson }
8468816f70bSRichard Henderson 
8478816f70bSRichard Henderson static bool trans_l_ori(DisasContext *dc, arg_rrk *a, uint32_t insn)
8488816f70bSRichard Henderson {
8498816f70bSRichard Henderson     check_r0_write(a->d);
8508816f70bSRichard Henderson     tcg_gen_ori_tl(cpu_R[a->d], cpu_R[a->a], a->k);
8518816f70bSRichard Henderson     return true;
8528816f70bSRichard Henderson }
8538816f70bSRichard Henderson 
8548816f70bSRichard Henderson static bool trans_l_xori(DisasContext *dc, arg_rri *a, uint32_t insn)
8558816f70bSRichard Henderson {
8568816f70bSRichard Henderson     check_r0_write(a->d);
8578816f70bSRichard Henderson     tcg_gen_xori_tl(cpu_R[a->d], cpu_R[a->a], a->i);
8588816f70bSRichard Henderson     return true;
8598816f70bSRichard Henderson }
8608816f70bSRichard Henderson 
8618816f70bSRichard Henderson static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a, uint32_t insn)
8628816f70bSRichard Henderson {
8638816f70bSRichard Henderson     check_r0_write(a->d);
8648816f70bSRichard Henderson 
8652ba65417SRichard Henderson     if (is_user(dc)) {
866fcf5ef2aSThomas Huth         gen_illegal_exception(dc);
8678816f70bSRichard Henderson     } else {
868c28fa81fSRichard Henderson         TCGv spr = tcg_temp_new();
869c28fa81fSRichard Henderson         tcg_gen_ori_tl(spr, cpu_R[a->a], a->k);
870c28fa81fSRichard Henderson         gen_helper_mfspr(cpu_R[a->d], cpu_env, cpu_R[a->d], spr);
871c28fa81fSRichard Henderson         tcg_temp_free(spr);
872fcf5ef2aSThomas Huth     }
8738816f70bSRichard Henderson     return true;
8748816f70bSRichard Henderson }
875fcf5ef2aSThomas Huth 
8768816f70bSRichard Henderson static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a, uint32_t insn)
877fcf5ef2aSThomas Huth {
8782ba65417SRichard Henderson     if (is_user(dc)) {
879fcf5ef2aSThomas Huth         gen_illegal_exception(dc);
8808816f70bSRichard Henderson     } else {
881c28fa81fSRichard Henderson         TCGv spr;
88201ec3ec9SRichard Henderson 
88301ec3ec9SRichard Henderson         /* For SR, we will need to exit the TB to recognize the new
88401ec3ec9SRichard Henderson          * exception state.  For NPC, in theory this counts as a branch
88501ec3ec9SRichard Henderson          * (although the SPR only exists for use by an ICE).  Save all
88601ec3ec9SRichard Henderson          * of the cpu state first, allowing it to be overwritten.
88701ec3ec9SRichard Henderson          */
88801ec3ec9SRichard Henderson         if (dc->delayed_branch) {
88901ec3ec9SRichard Henderson             tcg_gen_mov_tl(cpu_pc, jmp_pc);
89001ec3ec9SRichard Henderson             tcg_gen_discard_tl(jmp_pc);
89101ec3ec9SRichard Henderson         } else {
89201ec3ec9SRichard Henderson             tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
89301ec3ec9SRichard Henderson         }
89401ec3ec9SRichard Henderson         dc->base.is_jmp = DISAS_EXIT;
89501ec3ec9SRichard Henderson 
896c28fa81fSRichard Henderson         spr = tcg_temp_new();
897c28fa81fSRichard Henderson         tcg_gen_ori_tl(spr, cpu_R[a->a], a->k);
898c28fa81fSRichard Henderson         gen_helper_mtspr(cpu_env, spr, cpu_R[a->b]);
899c28fa81fSRichard Henderson         tcg_temp_free(spr);
900fcf5ef2aSThomas Huth     }
9018816f70bSRichard Henderson     return true;
902fcf5ef2aSThomas Huth }
903fcf5ef2aSThomas Huth 
90499d863d6SRichard Henderson static bool trans_l_mac(DisasContext *dc, arg_ab *a, uint32_t insn)
905fcf5ef2aSThomas Huth {
90699d863d6SRichard Henderson     gen_mac(dc, cpu_R[a->a], cpu_R[a->b]);
90799d863d6SRichard Henderson     return true;
908fcf5ef2aSThomas Huth }
90999d863d6SRichard Henderson 
91099d863d6SRichard Henderson static bool trans_l_msb(DisasContext *dc, arg_ab *a, uint32_t insn)
91199d863d6SRichard Henderson {
91299d863d6SRichard Henderson     gen_msb(dc, cpu_R[a->a], cpu_R[a->b]);
91399d863d6SRichard Henderson     return true;
91499d863d6SRichard Henderson }
91599d863d6SRichard Henderson 
91699d863d6SRichard Henderson static bool trans_l_macu(DisasContext *dc, arg_ab *a, uint32_t insn)
91799d863d6SRichard Henderson {
91899d863d6SRichard Henderson     gen_macu(dc, cpu_R[a->a], cpu_R[a->b]);
91999d863d6SRichard Henderson     return true;
92099d863d6SRichard Henderson }
92199d863d6SRichard Henderson 
92299d863d6SRichard Henderson static bool trans_l_msbu(DisasContext *dc, arg_ab *a, uint32_t insn)
92399d863d6SRichard Henderson {
92499d863d6SRichard Henderson     gen_msbu(dc, cpu_R[a->a], cpu_R[a->b]);
92599d863d6SRichard Henderson     return true;
926fcf5ef2aSThomas Huth }
927fcf5ef2aSThomas Huth 
928e20c2592SRichard Henderson static bool trans_l_slli(DisasContext *dc, arg_dal *a, uint32_t insn)
929fcf5ef2aSThomas Huth {
930e20c2592SRichard Henderson     check_r0_write(a->d);
931e20c2592SRichard Henderson     tcg_gen_shli_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
932e20c2592SRichard Henderson     return true;
933fcf5ef2aSThomas Huth }
934e20c2592SRichard Henderson 
935e20c2592SRichard Henderson static bool trans_l_srli(DisasContext *dc, arg_dal *a, uint32_t insn)
936e20c2592SRichard Henderson {
937e20c2592SRichard Henderson     check_r0_write(a->d);
938e20c2592SRichard Henderson     tcg_gen_shri_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
939e20c2592SRichard Henderson     return true;
940e20c2592SRichard Henderson }
941e20c2592SRichard Henderson 
942e20c2592SRichard Henderson static bool trans_l_srai(DisasContext *dc, arg_dal *a, uint32_t insn)
943e20c2592SRichard Henderson {
944e20c2592SRichard Henderson     check_r0_write(a->d);
945e20c2592SRichard Henderson     tcg_gen_sari_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
946e20c2592SRichard Henderson     return true;
947e20c2592SRichard Henderson }
948e20c2592SRichard Henderson 
949e20c2592SRichard Henderson static bool trans_l_rori(DisasContext *dc, arg_dal *a, uint32_t insn)
950e20c2592SRichard Henderson {
951e20c2592SRichard Henderson     check_r0_write(a->d);
952e20c2592SRichard Henderson     tcg_gen_rotri_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
953e20c2592SRichard Henderson     return true;
954fcf5ef2aSThomas Huth }
955fcf5ef2aSThomas Huth 
956e720a571SRichard Henderson static bool trans_l_movhi(DisasContext *dc, arg_l_movhi *a, uint32_t insn)
957fcf5ef2aSThomas Huth {
958e720a571SRichard Henderson     check_r0_write(a->d);
959e720a571SRichard Henderson     tcg_gen_movi_tl(cpu_R[a->d], a->k << 16);
960e720a571SRichard Henderson     return true;
961fcf5ef2aSThomas Huth }
962e720a571SRichard Henderson 
963e720a571SRichard Henderson static bool trans_l_macrc(DisasContext *dc, arg_l_macrc *a, uint32_t insn)
964e720a571SRichard Henderson {
965e720a571SRichard Henderson     check_r0_write(a->d);
966e720a571SRichard Henderson     tcg_gen_trunc_i64_tl(cpu_R[a->d], cpu_mac);
967e720a571SRichard Henderson     tcg_gen_movi_i64(cpu_mac, 0);
968e720a571SRichard Henderson     return true;
969fcf5ef2aSThomas Huth }
970fcf5ef2aSThomas Huth 
971fbb3e29aSRichard Henderson static bool trans_l_sfeq(DisasContext *dc, arg_ab *a, TCGCond cond)
972fcf5ef2aSThomas Huth {
973fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
974fbb3e29aSRichard Henderson     return true;
975fcf5ef2aSThomas Huth }
976fbb3e29aSRichard Henderson 
977fbb3e29aSRichard Henderson static bool trans_l_sfne(DisasContext *dc, arg_ab *a, TCGCond cond)
978fbb3e29aSRichard Henderson {
979fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
980fbb3e29aSRichard Henderson     return true;
981fbb3e29aSRichard Henderson }
982fbb3e29aSRichard Henderson 
983fbb3e29aSRichard Henderson static bool trans_l_sfgtu(DisasContext *dc, arg_ab *a, TCGCond cond)
984fbb3e29aSRichard Henderson {
985fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
986fbb3e29aSRichard Henderson     return true;
987fbb3e29aSRichard Henderson }
988fbb3e29aSRichard Henderson 
989fbb3e29aSRichard Henderson static bool trans_l_sfgeu(DisasContext *dc, arg_ab *a, TCGCond cond)
990fbb3e29aSRichard Henderson {
991fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
992fbb3e29aSRichard Henderson     return true;
993fbb3e29aSRichard Henderson }
994fbb3e29aSRichard Henderson 
995fbb3e29aSRichard Henderson static bool trans_l_sfltu(DisasContext *dc, arg_ab *a, TCGCond cond)
996fbb3e29aSRichard Henderson {
997fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
998fbb3e29aSRichard Henderson     return true;
999fbb3e29aSRichard Henderson }
1000fbb3e29aSRichard Henderson 
1001fbb3e29aSRichard Henderson static bool trans_l_sfleu(DisasContext *dc, arg_ab *a, TCGCond cond)
1002fbb3e29aSRichard Henderson {
1003fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
1004fbb3e29aSRichard Henderson     return true;
1005fbb3e29aSRichard Henderson }
1006fbb3e29aSRichard Henderson 
1007fbb3e29aSRichard Henderson static bool trans_l_sfgts(DisasContext *dc, arg_ab *a, TCGCond cond)
1008fbb3e29aSRichard Henderson {
1009fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
1010fbb3e29aSRichard Henderson     return true;
1011fbb3e29aSRichard Henderson }
1012fbb3e29aSRichard Henderson 
1013fbb3e29aSRichard Henderson static bool trans_l_sfges(DisasContext *dc, arg_ab *a, TCGCond cond)
1014fbb3e29aSRichard Henderson {
1015fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
1016fbb3e29aSRichard Henderson     return true;
1017fbb3e29aSRichard Henderson }
1018fbb3e29aSRichard Henderson 
1019fbb3e29aSRichard Henderson static bool trans_l_sflts(DisasContext *dc, arg_ab *a, TCGCond cond)
1020fbb3e29aSRichard Henderson {
1021fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
1022fbb3e29aSRichard Henderson     return true;
1023fbb3e29aSRichard Henderson }
1024fbb3e29aSRichard Henderson 
1025fbb3e29aSRichard Henderson static bool trans_l_sfles(DisasContext *dc, arg_ab *a, TCGCond cond)
1026fbb3e29aSRichard Henderson {
1027fbb3e29aSRichard Henderson     tcg_gen_setcond_tl(TCG_COND_LE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
1028fbb3e29aSRichard Henderson     return true;
1029fcf5ef2aSThomas Huth }
1030fcf5ef2aSThomas Huth 
1031032de4fcSRichard Henderson static bool trans_l_sfeqi(DisasContext *dc, arg_ai *a, TCGCond cond)
1032fcf5ef2aSThomas Huth {
1033032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[a->a], a->i);
1034032de4fcSRichard Henderson     return true;
1035fcf5ef2aSThomas Huth }
1036032de4fcSRichard Henderson 
1037032de4fcSRichard Henderson static bool trans_l_sfnei(DisasContext *dc, arg_ai *a, TCGCond cond)
1038032de4fcSRichard Henderson {
1039032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R[a->a], a->i);
1040032de4fcSRichard Henderson     return true;
1041032de4fcSRichard Henderson }
1042032de4fcSRichard Henderson 
1043032de4fcSRichard Henderson static bool trans_l_sfgtui(DisasContext *dc, arg_ai *a, TCGCond cond)
1044032de4fcSRichard Henderson {
1045032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[a->a], a->i);
1046032de4fcSRichard Henderson     return true;
1047032de4fcSRichard Henderson }
1048032de4fcSRichard Henderson 
1049032de4fcSRichard Henderson static bool trans_l_sfgeui(DisasContext *dc, arg_ai *a, TCGCond cond)
1050032de4fcSRichard Henderson {
1051032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[a->a], a->i);
1052032de4fcSRichard Henderson     return true;
1053032de4fcSRichard Henderson }
1054032de4fcSRichard Henderson 
1055032de4fcSRichard Henderson static bool trans_l_sfltui(DisasContext *dc, arg_ai *a, TCGCond cond)
1056032de4fcSRichard Henderson {
1057032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[a->a], a->i);
1058032de4fcSRichard Henderson     return true;
1059032de4fcSRichard Henderson }
1060032de4fcSRichard Henderson 
1061032de4fcSRichard Henderson static bool trans_l_sfleui(DisasContext *dc, arg_ai *a, TCGCond cond)
1062032de4fcSRichard Henderson {
1063032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[a->a], a->i);
1064032de4fcSRichard Henderson     return true;
1065032de4fcSRichard Henderson }
1066032de4fcSRichard Henderson 
1067032de4fcSRichard Henderson static bool trans_l_sfgtsi(DisasContext *dc, arg_ai *a, TCGCond cond)
1068032de4fcSRichard Henderson {
1069032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R[a->a], a->i);
1070032de4fcSRichard Henderson     return true;
1071032de4fcSRichard Henderson }
1072032de4fcSRichard Henderson 
1073032de4fcSRichard Henderson static bool trans_l_sfgesi(DisasContext *dc, arg_ai *a, TCGCond cond)
1074032de4fcSRichard Henderson {
1075032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R[a->a], a->i);
1076032de4fcSRichard Henderson     return true;
1077032de4fcSRichard Henderson }
1078032de4fcSRichard Henderson 
1079032de4fcSRichard Henderson static bool trans_l_sfltsi(DisasContext *dc, arg_ai *a, TCGCond cond)
1080032de4fcSRichard Henderson {
1081032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R[a->a], a->i);
1082032de4fcSRichard Henderson     return true;
1083032de4fcSRichard Henderson }
1084032de4fcSRichard Henderson 
1085032de4fcSRichard Henderson static bool trans_l_sflesi(DisasContext *dc, arg_ai *a, TCGCond cond)
1086032de4fcSRichard Henderson {
1087032de4fcSRichard Henderson     tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R[a->a], a->i);
1088032de4fcSRichard Henderson     return true;
1089fcf5ef2aSThomas Huth }
1090fcf5ef2aSThomas Huth 
10917de9729fSRichard Henderson static bool trans_l_sys(DisasContext *dc, arg_l_sys *a, uint32_t insn)
1092fcf5ef2aSThomas Huth {
10931ffa4bceSEmilio G. Cota     tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
1094fcf5ef2aSThomas Huth     gen_exception(dc, EXCP_SYSCALL);
10951ffa4bceSEmilio G. Cota     dc->base.is_jmp = DISAS_NORETURN;
10967de9729fSRichard Henderson     return true;
10977de9729fSRichard Henderson }
1098fcf5ef2aSThomas Huth 
10997de9729fSRichard Henderson static bool trans_l_trap(DisasContext *dc, arg_l_trap *a, uint32_t insn)
11007de9729fSRichard Henderson {
11011ffa4bceSEmilio G. Cota     tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
1102fcf5ef2aSThomas Huth     gen_exception(dc, EXCP_TRAP);
11031ffa4bceSEmilio G. Cota     dc->base.is_jmp = DISAS_NORETURN;
11047de9729fSRichard Henderson     return true;
11057de9729fSRichard Henderson }
1106fcf5ef2aSThomas Huth 
11077de9729fSRichard Henderson static bool trans_l_msync(DisasContext *dc, arg_l_msync *a, uint32_t insn)
11087de9729fSRichard Henderson {
110924fc5c0fSRichard Henderson     tcg_gen_mb(TCG_MO_ALL);
11107de9729fSRichard Henderson     return true;
1111fcf5ef2aSThomas Huth }
11127de9729fSRichard Henderson 
11137de9729fSRichard Henderson static bool trans_l_psync(DisasContext *dc, arg_l_psync *a, uint32_t insn)
11147de9729fSRichard Henderson {
11157de9729fSRichard Henderson     return true;
11167de9729fSRichard Henderson }
11177de9729fSRichard Henderson 
11187de9729fSRichard Henderson static bool trans_l_csync(DisasContext *dc, arg_l_csync *a, uint32_t insn)
11197de9729fSRichard Henderson {
11207de9729fSRichard Henderson     return true;
1121fcf5ef2aSThomas Huth }
1122fcf5ef2aSThomas Huth 
11238816f70bSRichard Henderson static bool trans_l_rfe(DisasContext *dc, arg_l_rfe *a, uint32_t insn)
11248816f70bSRichard Henderson {
11252ba65417SRichard Henderson     if (is_user(dc)) {
11268816f70bSRichard Henderson         gen_illegal_exception(dc);
11278816f70bSRichard Henderson     } else {
11288816f70bSRichard Henderson         gen_helper_rfe(cpu_env);
112964e46c95SRichard Henderson         dc->base.is_jmp = DISAS_EXIT;
11308816f70bSRichard Henderson     }
11318816f70bSRichard Henderson     return true;
11328816f70bSRichard Henderson }
11338816f70bSRichard Henderson 
11346fd204a2SRichard Henderson static void do_fp2(DisasContext *dc, arg_da *a,
11356fd204a2SRichard Henderson                    void (*fn)(TCGv, TCGv_env, TCGv))
1136fcf5ef2aSThomas Huth {
11376fd204a2SRichard Henderson     check_r0_write(a->d);
11386fd204a2SRichard Henderson     fn(cpu_R[a->d], cpu_env, cpu_R[a->a]);
11394e2d3007SRichard Henderson     gen_helper_update_fpcsr(cpu_env);
1140fcf5ef2aSThomas Huth }
11416fd204a2SRichard Henderson 
11426fd204a2SRichard Henderson static void do_fp3(DisasContext *dc, arg_dab *a,
11436fd204a2SRichard Henderson                    void (*fn)(TCGv, TCGv_env, TCGv, TCGv))
11446fd204a2SRichard Henderson {
11456fd204a2SRichard Henderson     check_r0_write(a->d);
11466fd204a2SRichard Henderson     fn(cpu_R[a->d], cpu_env, cpu_R[a->a], cpu_R[a->b]);
11476fd204a2SRichard Henderson     gen_helper_update_fpcsr(cpu_env);
11486fd204a2SRichard Henderson }
11496fd204a2SRichard Henderson 
11506fd204a2SRichard Henderson static void do_fpcmp(DisasContext *dc, arg_ab *a,
11516fd204a2SRichard Henderson                      void (*fn)(TCGv, TCGv_env, TCGv, TCGv),
11526fd204a2SRichard Henderson                      bool inv, bool swap)
11536fd204a2SRichard Henderson {
11546fd204a2SRichard Henderson     if (swap) {
11556fd204a2SRichard Henderson         fn(cpu_sr_f, cpu_env, cpu_R[a->b], cpu_R[a->a]);
11566fd204a2SRichard Henderson     } else {
11576fd204a2SRichard Henderson         fn(cpu_sr_f, cpu_env, cpu_R[a->a], cpu_R[a->b]);
11586fd204a2SRichard Henderson     }
11596fd204a2SRichard Henderson     if (inv) {
11606fd204a2SRichard Henderson         tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1);
11616fd204a2SRichard Henderson     }
11626fd204a2SRichard Henderson     gen_helper_update_fpcsr(cpu_env);
11636fd204a2SRichard Henderson }
11646fd204a2SRichard Henderson 
11656fd204a2SRichard Henderson static bool trans_lf_add_s(DisasContext *dc, arg_dab *a, uint32_t insn)
11666fd204a2SRichard Henderson {
11676fd204a2SRichard Henderson     do_fp3(dc, a, gen_helper_float_add_s);
11686fd204a2SRichard Henderson     return true;
11696fd204a2SRichard Henderson }
11706fd204a2SRichard Henderson 
11716fd204a2SRichard Henderson static bool trans_lf_sub_s(DisasContext *dc, arg_dab *a, uint32_t insn)
11726fd204a2SRichard Henderson {
11736fd204a2SRichard Henderson     do_fp3(dc, a, gen_helper_float_sub_s);
11746fd204a2SRichard Henderson     return true;
11756fd204a2SRichard Henderson }
11766fd204a2SRichard Henderson 
11776fd204a2SRichard Henderson static bool trans_lf_mul_s(DisasContext *dc, arg_dab *a, uint32_t insn)
11786fd204a2SRichard Henderson {
11796fd204a2SRichard Henderson     do_fp3(dc, a, gen_helper_float_mul_s);
11806fd204a2SRichard Henderson     return true;
11816fd204a2SRichard Henderson }
11826fd204a2SRichard Henderson 
11836fd204a2SRichard Henderson static bool trans_lf_div_s(DisasContext *dc, arg_dab *a, uint32_t insn)
11846fd204a2SRichard Henderson {
11856fd204a2SRichard Henderson     do_fp3(dc, a, gen_helper_float_div_s);
11866fd204a2SRichard Henderson     return true;
11876fd204a2SRichard Henderson }
11886fd204a2SRichard Henderson 
11896fd204a2SRichard Henderson static bool trans_lf_rem_s(DisasContext *dc, arg_dab *a, uint32_t insn)
11906fd204a2SRichard Henderson {
11916fd204a2SRichard Henderson     do_fp3(dc, a, gen_helper_float_rem_s);
11926fd204a2SRichard Henderson     return true;
11936fd204a2SRichard Henderson }
11946fd204a2SRichard Henderson 
11956fd204a2SRichard Henderson static bool trans_lf_itof_s(DisasContext *dc, arg_da *a, uint32_t insn)
11966fd204a2SRichard Henderson {
11976fd204a2SRichard Henderson     do_fp2(dc, a, gen_helper_itofs);
11986fd204a2SRichard Henderson     return true;
11996fd204a2SRichard Henderson }
12006fd204a2SRichard Henderson 
12016fd204a2SRichard Henderson static bool trans_lf_ftoi_s(DisasContext *dc, arg_da *a, uint32_t insn)
12026fd204a2SRichard Henderson {
12036fd204a2SRichard Henderson     do_fp2(dc, a, gen_helper_ftois);
12046fd204a2SRichard Henderson     return true;
12056fd204a2SRichard Henderson }
12066fd204a2SRichard Henderson 
12076fd204a2SRichard Henderson static bool trans_lf_madd_s(DisasContext *dc, arg_dab *a, uint32_t insn)
12086fd204a2SRichard Henderson {
12096fd204a2SRichard Henderson     check_r0_write(a->d);
12106fd204a2SRichard Henderson     gen_helper_float_madd_s(cpu_R[a->d], cpu_env, cpu_R[a->d],
12116fd204a2SRichard Henderson                             cpu_R[a->a], cpu_R[a->b]);
12126fd204a2SRichard Henderson     gen_helper_update_fpcsr(cpu_env);
12136fd204a2SRichard Henderson     return true;
12146fd204a2SRichard Henderson }
12156fd204a2SRichard Henderson 
12166fd204a2SRichard Henderson static bool trans_lf_sfeq_s(DisasContext *dc, arg_ab *a, uint32_t insn)
12176fd204a2SRichard Henderson {
12186fd204a2SRichard Henderson     do_fpcmp(dc, a, gen_helper_float_eq_s, false, false);
12196fd204a2SRichard Henderson     return true;
12206fd204a2SRichard Henderson }
12216fd204a2SRichard Henderson 
12226fd204a2SRichard Henderson static bool trans_lf_sfne_s(DisasContext *dc, arg_ab *a, uint32_t insn)
12236fd204a2SRichard Henderson {
12246fd204a2SRichard Henderson     do_fpcmp(dc, a, gen_helper_float_eq_s, true, false);
12256fd204a2SRichard Henderson     return true;
12266fd204a2SRichard Henderson }
12276fd204a2SRichard Henderson 
12286fd204a2SRichard Henderson static bool trans_lf_sfgt_s(DisasContext *dc, arg_ab *a, uint32_t insn)
12296fd204a2SRichard Henderson {
12306fd204a2SRichard Henderson     do_fpcmp(dc, a, gen_helper_float_lt_s, false, true);
12316fd204a2SRichard Henderson     return true;
12326fd204a2SRichard Henderson }
12336fd204a2SRichard Henderson 
12346fd204a2SRichard Henderson static bool trans_lf_sfge_s(DisasContext *dc, arg_ab *a, uint32_t insn)
12356fd204a2SRichard Henderson {
12366fd204a2SRichard Henderson     do_fpcmp(dc, a, gen_helper_float_le_s, false, true);
12376fd204a2SRichard Henderson     return true;
12386fd204a2SRichard Henderson }
12396fd204a2SRichard Henderson 
12406fd204a2SRichard Henderson static bool trans_lf_sflt_s(DisasContext *dc, arg_ab *a, uint32_t insn)
12416fd204a2SRichard Henderson {
12426fd204a2SRichard Henderson     do_fpcmp(dc, a, gen_helper_float_lt_s, false, false);
12436fd204a2SRichard Henderson     return true;
12446fd204a2SRichard Henderson }
12456fd204a2SRichard Henderson 
12466fd204a2SRichard Henderson static bool trans_lf_sfle_s(DisasContext *dc, arg_ab *a, uint32_t insn)
12476fd204a2SRichard Henderson {
12486fd204a2SRichard Henderson     do_fpcmp(dc, a, gen_helper_float_le_s, false, false);
12496fd204a2SRichard Henderson     return true;
1250fcf5ef2aSThomas Huth }
1251fcf5ef2aSThomas Huth 
1252a4fd3ec3SEmilio G. Cota static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1253fcf5ef2aSThomas Huth {
1254a4fd3ec3SEmilio G. Cota     DisasContext *dc = container_of(dcb, DisasContext, base);
12559c489ea6SLluís Vilanova     CPUOpenRISCState *env = cs->env_ptr;
1256a4fd3ec3SEmilio G. Cota     int bound;
1257fcf5ef2aSThomas Huth 
1258a4fd3ec3SEmilio G. Cota     dc->mem_idx = cpu_mmu_index(env, false);
12591ffa4bceSEmilio G. Cota     dc->tb_flags = dc->base.tb->flags;
1260a01deb36SRichard Henderson     dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0;
12618000ba56SRichard Henderson     dc->jmp_pc_imm = -1;
12628000ba56SRichard Henderson 
1263a4fd3ec3SEmilio G. Cota     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1264a4fd3ec3SEmilio G. Cota     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1265fcf5ef2aSThomas Huth }
1266fcf5ef2aSThomas Huth 
1267a4fd3ec3SEmilio G. Cota static void openrisc_tr_tb_start(DisasContextBase *db, CPUState *cs)
1268a4fd3ec3SEmilio G. Cota {
1269a4fd3ec3SEmilio G. Cota     DisasContext *dc = container_of(db, DisasContext, base);
1270fcf5ef2aSThomas Huth 
12716597c28dSRichard Henderson     /* Allow the TCG optimizer to see that R0 == 0,
12726597c28dSRichard Henderson        when it's true, which is the common case.  */
12736597c28dSRichard Henderson     if (dc->tb_flags & TB_FLAGS_R0_0) {
12746597c28dSRichard Henderson         cpu_R[0] = tcg_const_tl(0);
12756597c28dSRichard Henderson     } else {
12766597c28dSRichard Henderson         cpu_R[0] = cpu_R0;
12776597c28dSRichard Henderson     }
1278a4fd3ec3SEmilio G. Cota }
12796597c28dSRichard Henderson 
1280a4fd3ec3SEmilio G. Cota static void openrisc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
1281a4fd3ec3SEmilio G. Cota {
1282a4fd3ec3SEmilio G. Cota     DisasContext *dc = container_of(dcbase, DisasContext, base);
1283a4fd3ec3SEmilio G. Cota 
12841ffa4bceSEmilio G. Cota     tcg_gen_insn_start(dc->base.pc_next, (dc->delayed_branch ? 1 : 0)
1285a4fd3ec3SEmilio G. Cota                        | (dc->base.num_insns > 1 ? 2 : 0));
1286a4fd3ec3SEmilio G. Cota }
1287fcf5ef2aSThomas Huth 
1288a4fd3ec3SEmilio G. Cota static bool openrisc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
1289a4fd3ec3SEmilio G. Cota                                          const CPUBreakpoint *bp)
1290a4fd3ec3SEmilio G. Cota {
1291a4fd3ec3SEmilio G. Cota     DisasContext *dc = container_of(dcbase, DisasContext, base);
1292a4fd3ec3SEmilio G. Cota 
12931ffa4bceSEmilio G. Cota     tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
1294fcf5ef2aSThomas Huth     gen_exception(dc, EXCP_DEBUG);
12951ffa4bceSEmilio G. Cota     dc->base.is_jmp = DISAS_NORETURN;
1296fcf5ef2aSThomas Huth     /* The address covered by the breakpoint must be included in
1297fcf5ef2aSThomas Huth        [tb->pc, tb->pc + tb->size) in order to for it to be
1298fcf5ef2aSThomas Huth        properly cleared -- thus we increment the PC here so that
1299fcf5ef2aSThomas Huth        the logic setting tb->size below does the right thing.  */
13001ffa4bceSEmilio G. Cota     dc->base.pc_next += 4;
1301a4fd3ec3SEmilio G. Cota     return true;
1302fcf5ef2aSThomas Huth }
1303fcf5ef2aSThomas Huth 
1304a4fd3ec3SEmilio G. Cota static void openrisc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
1305a4fd3ec3SEmilio G. Cota {
1306a4fd3ec3SEmilio G. Cota     DisasContext *dc = container_of(dcbase, DisasContext, base);
1307a4fd3ec3SEmilio G. Cota     OpenRISCCPU *cpu = OPENRISC_CPU(cs);
1308c7b6f54bSRichard Henderson     uint32_t insn = cpu_ldl_code(&cpu->env, dc->base.pc_next);
1309a4fd3ec3SEmilio G. Cota 
1310c7b6f54bSRichard Henderson     if (!decode(dc, insn)) {
1311c7b6f54bSRichard Henderson         gen_illegal_exception(dc);
1312c7b6f54bSRichard Henderson     }
13131ffa4bceSEmilio G. Cota     dc->base.pc_next += 4;
131424c32852SRichard Henderson 
13158000ba56SRichard Henderson     /* When exiting the delay slot normally, exit via jmp_pc.
13168000ba56SRichard Henderson      * For DISAS_NORETURN, we have raised an exception and already exited.
13178000ba56SRichard Henderson      * For DISAS_EXIT, we found l.rfe in a delay slot.  There's nothing
13188000ba56SRichard Henderson      * in the manual saying this is illegal, but it surely it should.
13198000ba56SRichard Henderson      * At least or1ksim overrides pcnext and ignores the branch.
13208000ba56SRichard Henderson      */
13218000ba56SRichard Henderson     if (dc->delayed_branch
13228000ba56SRichard Henderson         && --dc->delayed_branch == 0
13238000ba56SRichard Henderson         && dc->base.is_jmp == DISAS_NEXT) {
13248000ba56SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1325fcf5ef2aSThomas Huth     }
1326a4fd3ec3SEmilio G. Cota }
1327fcf5ef2aSThomas Huth 
1328a4fd3ec3SEmilio G. Cota static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
1329a4fd3ec3SEmilio G. Cota {
1330a4fd3ec3SEmilio G. Cota     DisasContext *dc = container_of(dcbase, DisasContext, base);
13318000ba56SRichard Henderson     target_ulong jmp_dest;
133224c32852SRichard Henderson 
1333e0a369cfSRichard Henderson     /* If we have already exited the TB, nothing following has effect.  */
1334e0a369cfSRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1335e0a369cfSRichard Henderson         return;
1336e0a369cfSRichard Henderson     }
1337e0a369cfSRichard Henderson 
13388000ba56SRichard Henderson     /* Adjust the delayed branch state for the next TB.  */
1339a01deb36SRichard Henderson     if ((dc->tb_flags & TB_FLAGS_DFLAG ? 1 : 0) != (dc->delayed_branch != 0)) {
1340a01deb36SRichard Henderson         tcg_gen_movi_i32(cpu_dflag, dc->delayed_branch != 0);
1341a01deb36SRichard Henderson     }
1342a01deb36SRichard Henderson 
13438000ba56SRichard Henderson     /* For DISAS_TOO_MANY, jump to the next insn.  */
13448000ba56SRichard Henderson     jmp_dest = dc->base.pc_next;
13458000ba56SRichard Henderson     tcg_gen_movi_tl(cpu_ppc, jmp_dest - 4);
13468000ba56SRichard Henderson 
13471ffa4bceSEmilio G. Cota     switch (dc->base.is_jmp) {
13488000ba56SRichard Henderson     case DISAS_JUMP:
13498000ba56SRichard Henderson         jmp_dest = dc->jmp_pc_imm;
13508000ba56SRichard Henderson         if (jmp_dest == -1) {
13518000ba56SRichard Henderson             /* The jump destination is indirect/computed; use jmp_pc.  */
13528000ba56SRichard Henderson             tcg_gen_mov_tl(cpu_pc, jmp_pc);
13538000ba56SRichard Henderson             tcg_gen_discard_tl(jmp_pc);
13548000ba56SRichard Henderson             if (unlikely(dc->base.singlestep_enabled)) {
13558000ba56SRichard Henderson                 gen_exception(dc, EXCP_DEBUG);
13568000ba56SRichard Henderson             } else {
13578000ba56SRichard Henderson                 tcg_gen_lookup_and_goto_ptr();
13588000ba56SRichard Henderson             }
1359fcf5ef2aSThomas Huth             break;
13608000ba56SRichard Henderson         }
13618000ba56SRichard Henderson         /* The jump destination is direct; use jmp_pc_imm.
13628000ba56SRichard Henderson            However, we will have stored into jmp_pc as well;
13638000ba56SRichard Henderson            we know now that it wasn't needed.  */
13648000ba56SRichard Henderson         tcg_gen_discard_tl(jmp_pc);
13658000ba56SRichard Henderson         /* fallthru */
13668000ba56SRichard Henderson 
13678000ba56SRichard Henderson     case DISAS_TOO_MANY:
13688000ba56SRichard Henderson         if (unlikely(dc->base.singlestep_enabled)) {
13698000ba56SRichard Henderson             tcg_gen_movi_tl(cpu_pc, jmp_dest);
13708000ba56SRichard Henderson             gen_exception(dc, EXCP_DEBUG);
13718000ba56SRichard Henderson         } else if ((dc->base.pc_first ^ jmp_dest) & TARGET_PAGE_MASK) {
13728000ba56SRichard Henderson             tcg_gen_movi_tl(cpu_pc, jmp_dest);
13738000ba56SRichard Henderson             tcg_gen_lookup_and_goto_ptr();
13748000ba56SRichard Henderson         } else {
13758000ba56SRichard Henderson             tcg_gen_goto_tb(0);
13768000ba56SRichard Henderson             tcg_gen_movi_tl(cpu_pc, jmp_dest);
13778000ba56SRichard Henderson             tcg_gen_exit_tb(dc->base.tb, 0);
13788000ba56SRichard Henderson         }
13798000ba56SRichard Henderson         break;
13808000ba56SRichard Henderson 
138164e46c95SRichard Henderson     case DISAS_EXIT:
1382e0a369cfSRichard Henderson         if (unlikely(dc->base.singlestep_enabled)) {
1383e0a369cfSRichard Henderson             gen_exception(dc, EXCP_DEBUG);
1384e0a369cfSRichard Henderson         } else {
138507ea28b4SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1386e0a369cfSRichard Henderson         }
1387fcf5ef2aSThomas Huth         break;
1388a4fd3ec3SEmilio G. Cota     default:
1389a4fd3ec3SEmilio G. Cota         g_assert_not_reached();
1390a4fd3ec3SEmilio G. Cota     }
1391fcf5ef2aSThomas Huth }
1392fcf5ef2aSThomas Huth 
1393a4fd3ec3SEmilio G. Cota static void openrisc_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
1394a4fd3ec3SEmilio G. Cota {
1395a4fd3ec3SEmilio G. Cota     DisasContext *s = container_of(dcbase, DisasContext, base);
1396fcf5ef2aSThomas Huth 
1397a4fd3ec3SEmilio G. Cota     qemu_log("IN: %s\n", lookup_symbol(s->base.pc_first));
1398a4fd3ec3SEmilio G. Cota     log_target_disas(cs, s->base.pc_first, s->base.tb->size);
1399fcf5ef2aSThomas Huth }
1400a4fd3ec3SEmilio G. Cota 
1401a4fd3ec3SEmilio G. Cota static const TranslatorOps openrisc_tr_ops = {
1402a4fd3ec3SEmilio G. Cota     .init_disas_context = openrisc_tr_init_disas_context,
1403a4fd3ec3SEmilio G. Cota     .tb_start           = openrisc_tr_tb_start,
1404a4fd3ec3SEmilio G. Cota     .insn_start         = openrisc_tr_insn_start,
1405a4fd3ec3SEmilio G. Cota     .breakpoint_check   = openrisc_tr_breakpoint_check,
1406a4fd3ec3SEmilio G. Cota     .translate_insn     = openrisc_tr_translate_insn,
1407a4fd3ec3SEmilio G. Cota     .tb_stop            = openrisc_tr_tb_stop,
1408a4fd3ec3SEmilio G. Cota     .disas_log          = openrisc_tr_disas_log,
1409a4fd3ec3SEmilio G. Cota };
1410a4fd3ec3SEmilio G. Cota 
1411a4fd3ec3SEmilio G. Cota void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
1412a4fd3ec3SEmilio G. Cota {
1413a4fd3ec3SEmilio G. Cota     DisasContext ctx;
1414a4fd3ec3SEmilio G. Cota 
1415a4fd3ec3SEmilio G. Cota     translator_loop(&openrisc_tr_ops, &ctx.base, cs, tb);
1416fcf5ef2aSThomas Huth }
1417fcf5ef2aSThomas Huth 
1418fcf5ef2aSThomas Huth void openrisc_cpu_dump_state(CPUState *cs, FILE *f,
1419fcf5ef2aSThomas Huth                              fprintf_function cpu_fprintf,
1420fcf5ef2aSThomas Huth                              int flags)
1421fcf5ef2aSThomas Huth {
1422fcf5ef2aSThomas Huth     OpenRISCCPU *cpu = OPENRISC_CPU(cs);
1423fcf5ef2aSThomas Huth     CPUOpenRISCState *env = &cpu->env;
1424fcf5ef2aSThomas Huth     int i;
1425fcf5ef2aSThomas Huth 
1426fcf5ef2aSThomas Huth     cpu_fprintf(f, "PC=%08x\n", env->pc);
1427fcf5ef2aSThomas Huth     for (i = 0; i < 32; ++i) {
1428d89e71e8SStafford Horne         cpu_fprintf(f, "R%02d=%08x%c", i, cpu_get_gpr(env, i),
1429fcf5ef2aSThomas Huth                     (i % 4) == 3 ? '\n' : ' ');
1430fcf5ef2aSThomas Huth     }
1431fcf5ef2aSThomas Huth }
1432fcf5ef2aSThomas Huth 
1433fcf5ef2aSThomas Huth void restore_state_to_opc(CPUOpenRISCState *env, TranslationBlock *tb,
1434fcf5ef2aSThomas Huth                           target_ulong *data)
1435fcf5ef2aSThomas Huth {
1436fcf5ef2aSThomas Huth     env->pc = data[0];
1437a01deb36SRichard Henderson     env->dflag = data[1] & 1;
1438a01deb36SRichard Henderson     if (data[1] & 2) {
143924c32852SRichard Henderson         env->ppc = env->pc - 4;
144024c32852SRichard Henderson     }
1441fcf5ef2aSThomas Huth }
1442