]> git.ipfire.org Git - thirdparty/qemu.git/blame - target/sparc/translate.c
target/sparc: Remove CC_OP_DIV
[thirdparty/qemu.git] / target / sparc / translate.c
CommitLineData
7a3f1944
FB
1/*
2 SPARC translation
3
4 Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
3475187d 5 Copyright (C) 2003-2005 Fabrice Bellard
7a3f1944
FB
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
5650b549 10 version 2.1 of the License, or (at your option) any later version.
7a3f1944
FB
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
8167ee88 18 License along with this library; if not, see <http://www.gnu.org/licenses/>.
7a3f1944
FB
19 */
20
db5ebe5f 21#include "qemu/osdep.h"
7a3f1944
FB
22
23#include "cpu.h"
76cad711 24#include "disas/disas.h"
2ef6175a 25#include "exec/helper-proto.h"
63c91552 26#include "exec/exec-all.h"
dcb32f1d 27#include "tcg/tcg-op.h"
fafba1bb 28#include "tcg/tcg-op-gvec.h"
2ef6175a 29#include "exec/helper-gen.h"
c5e6ccdf 30#include "exec/translator.h"
508127e2 31#include "exec/log.h"
0cc1f4bf 32#include "asi.h"
a7e30d84 33
d53106c9
RH
34#define HELPER_H "helper.h"
35#include "exec/helper-info.c.inc"
36#undef HELPER_H
a7e30d84 37
668bb9b7
RH
38#ifdef TARGET_SPARC64
39# define gen_helper_rdpsr(D, E) qemu_build_not_reached()
86b82fe0 40# define gen_helper_rett(E) qemu_build_not_reached()
0faef01b 41# define gen_helper_power_down(E) qemu_build_not_reached()
25524734 42# define gen_helper_wrpsr(E, S) qemu_build_not_reached()
668bb9b7 43#else
0faef01b 44# define gen_helper_clear_softint(E, S) qemu_build_not_reached()
8f75b8a4 45# define gen_helper_done(E) qemu_build_not_reached()
c6d83e4f 46# define gen_helper_fabsd(D, S) qemu_build_not_reached()
e8325dc0 47# define gen_helper_flushw(E) qemu_build_not_reached()
c6d83e4f 48# define gen_helper_fnegd(D, S) qemu_build_not_reached()
af25071c 49# define gen_helper_rdccr(D, E) qemu_build_not_reached()
5d617bfb 50# define gen_helper_rdcwp(D, E) qemu_build_not_reached()
25524734 51# define gen_helper_restored(E) qemu_build_not_reached()
8f75b8a4 52# define gen_helper_retry(E) qemu_build_not_reached()
25524734 53# define gen_helper_saved(E) qemu_build_not_reached()
4ee85ea9 54# define gen_helper_sdivx(D, E, A, B) qemu_build_not_reached()
0faef01b 55# define gen_helper_set_softint(E, S) qemu_build_not_reached()
af25071c 56# define gen_helper_tick_get_count(D, E, T, C) qemu_build_not_reached()
9422278e 57# define gen_helper_tick_set_count(P, S) qemu_build_not_reached()
bb97f2f5 58# define gen_helper_tick_set_limit(P, S) qemu_build_not_reached()
4ee85ea9 59# define gen_helper_udivx(D, E, A, B) qemu_build_not_reached()
0faef01b 60# define gen_helper_wrccr(E, S) qemu_build_not_reached()
9422278e
RH
61# define gen_helper_wrcwp(E, S) qemu_build_not_reached()
62# define gen_helper_wrgl(E, S) qemu_build_not_reached()
0faef01b 63# define gen_helper_write_softint(E, S) qemu_build_not_reached()
9422278e
RH
64# define gen_helper_wrpil(E, S) qemu_build_not_reached()
65# define gen_helper_wrpstate(E, S) qemu_build_not_reached()
f4e18df5 66# define gen_helper_fabsq ({ qemu_build_not_reached(); NULL; })
e2fa6bd1
RH
67# define gen_helper_fcmpeq16 ({ qemu_build_not_reached(); NULL; })
68# define gen_helper_fcmpeq32 ({ qemu_build_not_reached(); NULL; })
69# define gen_helper_fcmpgt16 ({ qemu_build_not_reached(); NULL; })
70# define gen_helper_fcmpgt32 ({ qemu_build_not_reached(); NULL; })
71# define gen_helper_fcmple16 ({ qemu_build_not_reached(); NULL; })
72# define gen_helper_fcmple32 ({ qemu_build_not_reached(); NULL; })
73# define gen_helper_fcmpne16 ({ qemu_build_not_reached(); NULL; })
74# define gen_helper_fcmpne32 ({ qemu_build_not_reached(); NULL; })
8aa418b3 75# define gen_helper_fdtox ({ qemu_build_not_reached(); NULL; })
e06c9f83
RH
76# define gen_helper_fexpand ({ qemu_build_not_reached(); NULL; })
77# define gen_helper_fmul8sux16 ({ qemu_build_not_reached(); NULL; })
78# define gen_helper_fmul8ulx16 ({ qemu_build_not_reached(); NULL; })
79# define gen_helper_fmul8x16al ({ qemu_build_not_reached(); NULL; })
80# define gen_helper_fmul8x16au ({ qemu_build_not_reached(); NULL; })
81# define gen_helper_fmul8x16 ({ qemu_build_not_reached(); NULL; })
82# define gen_helper_fmuld8sux16 ({ qemu_build_not_reached(); NULL; })
83# define gen_helper_fmuld8ulx16 ({ qemu_build_not_reached(); NULL; })
f4e18df5 84# define gen_helper_fnegq ({ qemu_build_not_reached(); NULL; })
e06c9f83 85# define gen_helper_fpmerge ({ qemu_build_not_reached(); NULL; })
1617586f 86# define gen_helper_fqtox ({ qemu_build_not_reached(); NULL; })
199d43ef 87# define gen_helper_fstox ({ qemu_build_not_reached(); NULL; })
8aa418b3 88# define gen_helper_fxtod ({ qemu_build_not_reached(); NULL; })
7b8e3e1a 89# define gen_helper_fxtoq ({ qemu_build_not_reached(); NULL; })
f4e18df5 90# define gen_helper_fxtos ({ qemu_build_not_reached(); NULL; })
afb04344 91# define gen_helper_pdist ({ qemu_build_not_reached(); NULL; })
da681406
RH
92# define FSR_LDXFSR_MASK 0
93# define FSR_LDXFSR_OLDMASK 0
668bb9b7 94# define MAXTL_MASK 0
af25071c
RH
95#endif
96
633c4283
RH
97/* Dynamic PC, must exit to main loop. */
98#define DYNAMIC_PC 1
99/* Dynamic PC, one of two values according to jump_pc[T2]. */
100#define JUMP_PC 2
101/* Dynamic PC, may lookup next TB. */
102#define DYNAMIC_PC_LOOKUP 3
72cbca10 103
46bb0137
MCA
104#define DISAS_EXIT DISAS_TARGET_0
105
1a2fb1c0 106/* global register indexes */
1bcea73e 107static TCGv_ptr cpu_regwptr;
25517f99
PB
108static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst;
109static TCGv_i32 cpu_cc_op;
d2dc4069
RH
110static TCGv cpu_fsr, cpu_pc, cpu_npc;
111static TCGv cpu_regs[32];
255e1fcb 112static TCGv cpu_y;
255e1fcb 113static TCGv cpu_tbr;
5793f2a4 114static TCGv cpu_cond;
2a1905c7
RH
115static TCGv cpu_cc_N;
116static TCGv cpu_cc_V;
117static TCGv cpu_icc_Z;
118static TCGv cpu_icc_C;
dc99a3f2 119#ifdef TARGET_SPARC64
2a1905c7
RH
120static TCGv cpu_xcc_Z;
121static TCGv cpu_xcc_C;
122static TCGv_i32 cpu_fprs;
a7812ae4 123static TCGv cpu_gsr;
255e1fcb 124#else
af25071c
RH
125# define cpu_fprs ({ qemu_build_not_reached(); (TCGv)NULL; })
126# define cpu_gsr ({ qemu_build_not_reached(); (TCGv)NULL; })
dc99a3f2 127#endif
2a1905c7
RH
128
129#ifdef TARGET_SPARC64
130#define cpu_cc_Z cpu_xcc_Z
131#define cpu_cc_C cpu_xcc_C
132#else
133#define cpu_cc_Z cpu_icc_Z
134#define cpu_cc_C cpu_icc_C
135#define cpu_xcc_Z ({ qemu_build_not_reached(); NULL; })
136#define cpu_xcc_C ({ qemu_build_not_reached(); NULL; })
137#endif
138
714547bb 139/* Floating point registers */
30038fd8 140static TCGv_i64 cpu_fpr[TARGET_DPREGS];
1a2fb1c0 141
af25071c
RH
142#define env_field_offsetof(X) offsetof(CPUSPARCState, X)
143#ifdef TARGET_SPARC64
cd6269f7 144# define env32_field_offsetof(X) ({ qemu_build_not_reached(); 0; })
af25071c
RH
145# define env64_field_offsetof(X) env_field_offsetof(X)
146#else
cd6269f7 147# define env32_field_offsetof(X) env_field_offsetof(X)
af25071c
RH
148# define env64_field_offsetof(X) ({ qemu_build_not_reached(); 0; })
149#endif
150
186e7890
RH
151typedef struct DisasDelayException {
152 struct DisasDelayException *next;
153 TCGLabel *lab;
154 TCGv_i32 excp;
155 /* Saved state at parent insn. */
156 target_ulong pc;
157 target_ulong npc;
158} DisasDelayException;
159
7a3f1944 160typedef struct DisasContext {
af00be49 161 DisasContextBase base;
0f8a249a
BS
162 target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */
163 target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */
72cbca10 164 target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
e8af50a3 165 int mem_idx;
c9b459aa
AT
166 bool fpu_enabled;
167 bool address_mask_32bit;
c9b459aa
AT
168#ifndef CONFIG_USER_ONLY
169 bool supervisor;
170#ifdef TARGET_SPARC64
171 bool hypervisor;
172#endif
173#endif
174
8393617c 175 uint32_t cc_op; /* current CC operation */
5578ceab 176 sparc_def_t *def;
a6d567e5 177#ifdef TARGET_SPARC64
f9c816c0 178 int fprs_dirty;
a6d567e5
RH
179 int asi;
180#endif
186e7890 181 DisasDelayException *delay_excp_list;
7a3f1944
FB
182} DisasContext;
183
416fcaea
RH
184typedef struct {
185 TCGCond cond;
186 bool is_bool;
416fcaea
RH
187 TCGv c1, c2;
188} DisasCompare;
189
3475187d 190// This function uses non-native bit order
dc1a6971
BS
191#define GET_FIELD(X, FROM, TO) \
192 ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
7a3f1944 193
3475187d 194// This function uses the order in the manuals, i.e. bit 0 is 2^0
dc1a6971 195#define GET_FIELD_SP(X, FROM, TO) \
3475187d
FB
196 GET_FIELD(X, 31 - (TO), 31 - (FROM))
197
198#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
46d38ba8 199#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1))
3475187d
FB
200
201#ifdef TARGET_SPARC64
0387d928 202#define DFPREG(r) (((r & 1) << 5) | (r & 0x1e))
1f587329 203#define QFPREG(r) (((r & 1) << 5) | (r & 0x1c))
3475187d 204#else
c185970a 205#define DFPREG(r) (r & 0x1e)
1f587329 206#define QFPREG(r) (r & 0x1c)
3475187d
FB
207#endif
208
b158a785
BS
209#define UA2005_HTRAP_MASK 0xff
210#define V8_TRAP_MASK 0x7f
211
7a3f1944
FB
212#define IS_IMM (insn & (1<<13))
213
0c2e96c1 214static void gen_update_fprs_dirty(DisasContext *dc, int rd)
141ae5c1
RH
215{
216#if defined(TARGET_SPARC64)
f9c816c0
RH
217 int bit = (rd < 32) ? 1 : 2;
218 /* If we know we've already set this bit within the TB,
219 we can avoid setting it again. */
220 if (!(dc->fprs_dirty & bit)) {
221 dc->fprs_dirty |= bit;
222 tcg_gen_ori_i32(cpu_fprs, cpu_fprs, bit);
223 }
141ae5c1
RH
224#endif
225}
226
ff07ec83 227/* floating point registers moves */
208ae657
RH
228static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src)
229{
36ab4623 230 TCGv_i32 ret = tcg_temp_new_i32();
30038fd8 231 if (src & 1) {
dc41aa7d 232 tcg_gen_extrl_i64_i32(ret, cpu_fpr[src / 2]);
30038fd8 233 } else {
dc41aa7d 234 tcg_gen_extrh_i64_i32(ret, cpu_fpr[src / 2]);
30038fd8 235 }
dc41aa7d 236 return ret;
208ae657
RH
237}
238
239static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
240{
8e7bbc75
RH
241 TCGv_i64 t = tcg_temp_new_i64();
242
243 tcg_gen_extu_i32_i64(t, v);
30038fd8
RH
244 tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t,
245 (dst & 1 ? 0 : 32), 32);
f9c816c0 246 gen_update_fprs_dirty(dc, dst);
208ae657
RH
247}
248
ba5f5179 249static TCGv_i32 gen_dest_fpr_F(DisasContext *dc)
208ae657 250{
36ab4623 251 return tcg_temp_new_i32();
208ae657
RH
252}
253
96eda024
RH
254static TCGv_i64 gen_load_fpr_D(DisasContext *dc, unsigned int src)
255{
96eda024 256 src = DFPREG(src);
30038fd8 257 return cpu_fpr[src / 2];
96eda024
RH
258}
259
260static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v)
261{
262 dst = DFPREG(dst);
30038fd8 263 tcg_gen_mov_i64(cpu_fpr[dst / 2], v);
f9c816c0 264 gen_update_fprs_dirty(dc, dst);
96eda024
RH
265}
266
3886b8a3 267static TCGv_i64 gen_dest_fpr_D(DisasContext *dc, unsigned int dst)
96eda024 268{
3886b8a3 269 return cpu_fpr[DFPREG(dst) / 2];
96eda024
RH
270}
271
ff07ec83
BS
272static void gen_op_load_fpr_QT0(unsigned int src)
273{
ad75a51e 274 tcg_gen_st_i64(cpu_fpr[src / 2], tcg_env, offsetof(CPUSPARCState, qt0) +
30038fd8 275 offsetof(CPU_QuadU, ll.upper));
ad75a51e 276 tcg_gen_st_i64(cpu_fpr[src/2 + 1], tcg_env, offsetof(CPUSPARCState, qt0) +
30038fd8 277 offsetof(CPU_QuadU, ll.lower));
ff07ec83
BS
278}
279
280static void gen_op_load_fpr_QT1(unsigned int src)
281{
ad75a51e 282 tcg_gen_st_i64(cpu_fpr[src / 2], tcg_env, offsetof(CPUSPARCState, qt1) +
30038fd8 283 offsetof(CPU_QuadU, ll.upper));
ad75a51e 284 tcg_gen_st_i64(cpu_fpr[src/2 + 1], tcg_env, offsetof(CPUSPARCState, qt1) +
30038fd8 285 offsetof(CPU_QuadU, ll.lower));
ff07ec83
BS
286}
287
288static void gen_op_store_QT0_fpr(unsigned int dst)
289{
ad75a51e 290 tcg_gen_ld_i64(cpu_fpr[dst / 2], tcg_env, offsetof(CPUSPARCState, qt0) +
30038fd8 291 offsetof(CPU_QuadU, ll.upper));
ad75a51e 292 tcg_gen_ld_i64(cpu_fpr[dst/2 + 1], tcg_env, offsetof(CPUSPARCState, qt0) +
30038fd8 293 offsetof(CPU_QuadU, ll.lower));
ff07ec83 294}
1f587329 295
81ad8ba2
BS
296/* moves */
297#ifdef CONFIG_USER_ONLY
3475187d 298#define supervisor(dc) 0
e9ebed4d 299#define hypervisor(dc) 0
3475187d 300#else
81ad8ba2 301#ifdef TARGET_SPARC64
c9b459aa
AT
302#define hypervisor(dc) (dc->hypervisor)
303#define supervisor(dc) (dc->supervisor | dc->hypervisor)
6f27aba6 304#else
c9b459aa 305#define supervisor(dc) (dc->supervisor)
668bb9b7 306#define hypervisor(dc) 0
3475187d 307#endif
81ad8ba2
BS
308#endif
309
b1bc09ea
RH
310#if !defined(TARGET_SPARC64)
311# define AM_CHECK(dc) false
312#elif defined(TARGET_ABI32)
313# define AM_CHECK(dc) true
314#elif defined(CONFIG_USER_ONLY)
315# define AM_CHECK(dc) false
1a2fb1c0 316#else
b1bc09ea 317# define AM_CHECK(dc) ((dc)->address_mask_32bit)
1a2fb1c0 318#endif
3391c818 319
0c2e96c1 320static void gen_address_mask(DisasContext *dc, TCGv addr)
2cade6a3 321{
b1bc09ea 322 if (AM_CHECK(dc)) {
2cade6a3 323 tcg_gen_andi_tl(addr, addr, 0xffffffffULL);
b1bc09ea 324 }
2cade6a3
BS
325}
326
23ada1b1
RH
327static target_ulong address_mask_i(DisasContext *dc, target_ulong addr)
328{
329 return AM_CHECK(dc) ? (uint32_t)addr : addr;
330}
331
0c2e96c1 332static TCGv gen_load_gpr(DisasContext *dc, int reg)
88023616 333{
d2dc4069
RH
334 if (reg > 0) {
335 assert(reg < 32);
336 return cpu_regs[reg];
337 } else {
52123f14 338 TCGv t = tcg_temp_new();
d2dc4069 339 tcg_gen_movi_tl(t, 0);
88023616 340 return t;
88023616
RH
341 }
342}
343
0c2e96c1 344static void gen_store_gpr(DisasContext *dc, int reg, TCGv v)
88023616
RH
345{
346 if (reg > 0) {
d2dc4069
RH
347 assert(reg < 32);
348 tcg_gen_mov_tl(cpu_regs[reg], v);
88023616
RH
349 }
350}
351
0c2e96c1 352static TCGv gen_dest_gpr(DisasContext *dc, int reg)
88023616 353{
d2dc4069
RH
354 if (reg > 0) {
355 assert(reg < 32);
356 return cpu_regs[reg];
88023616 357 } else {
52123f14 358 return tcg_temp_new();
88023616
RH
359 }
360}
361
5645aa2e 362static bool use_goto_tb(DisasContext *s, target_ulong pc, target_ulong npc)
90aa39a1 363{
5645aa2e
RH
364 return translator_use_goto_tb(&s->base, pc) &&
365 translator_use_goto_tb(&s->base, npc);
90aa39a1
SF
366}
367
5645aa2e
RH
368static void gen_goto_tb(DisasContext *s, int tb_num,
369 target_ulong pc, target_ulong npc)
6e256c93 370{
90aa39a1 371 if (use_goto_tb(s, pc, npc)) {
6e256c93 372 /* jump to same page: we can use a direct jump */
57fec1fe 373 tcg_gen_goto_tb(tb_num);
2f5680ee
BS
374 tcg_gen_movi_tl(cpu_pc, pc);
375 tcg_gen_movi_tl(cpu_npc, npc);
07ea28b4 376 tcg_gen_exit_tb(s->base.tb, tb_num);
6e256c93 377 } else {
f67ccb2f 378 /* jump to another page: we can use an indirect jump */
2f5680ee
BS
379 tcg_gen_movi_tl(cpu_pc, pc);
380 tcg_gen_movi_tl(cpu_npc, npc);
f67ccb2f 381 tcg_gen_lookup_and_goto_ptr();
6e256c93
FB
382 }
383}
384
0c2e96c1 385static void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
dc99a3f2 386{
4af984a7 387 tcg_gen_mov_tl(cpu_cc_src, src1);
6f551262 388 tcg_gen_mov_tl(cpu_cc_src2, src2);
5c6a0628 389 tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
bdf9f35d 390 tcg_gen_mov_tl(dst, cpu_cc_dst);
41d72852
BS
391}
392
70c48285 393static TCGv_i32 gen_add32_carry32(void)
dc99a3f2 394{
70c48285
RH
395 TCGv_i32 carry_32, cc_src1_32, cc_src2_32;
396
397 /* Carry is computed from a previous add: (dst < src) */
398#if TARGET_LONG_BITS == 64
399 cc_src1_32 = tcg_temp_new_i32();
400 cc_src2_32 = tcg_temp_new_i32();
ecc7b3aa
RH
401 tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_dst);
402 tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src);
70c48285
RH
403#else
404 cc_src1_32 = cpu_cc_dst;
405 cc_src2_32 = cpu_cc_src;
406#endif
407
408 carry_32 = tcg_temp_new_i32();
409 tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32);
410
70c48285 411 return carry_32;
41d72852
BS
412}
413
70c48285 414static TCGv_i32 gen_sub32_carry32(void)
41d72852 415{
70c48285
RH
416 TCGv_i32 carry_32, cc_src1_32, cc_src2_32;
417
418 /* Carry is computed from a previous borrow: (src1 < src2) */
419#if TARGET_LONG_BITS == 64
420 cc_src1_32 = tcg_temp_new_i32();
421 cc_src2_32 = tcg_temp_new_i32();
ecc7b3aa
RH
422 tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_src);
423 tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src2);
70c48285
RH
424#else
425 cc_src1_32 = cpu_cc_src;
426 cc_src2_32 = cpu_cc_src2;
427#endif
428
429 carry_32 = tcg_temp_new_i32();
430 tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32);
431
70c48285
RH
432 return carry_32;
433}
434
420a187d
RH
435static void gen_op_addc_int(TCGv dst, TCGv src1, TCGv src2,
436 TCGv_i32 carry_32, bool update_cc)
70c48285 437{
420a187d 438 tcg_gen_add_tl(dst, src1, src2);
70c48285 439
420a187d
RH
440#ifdef TARGET_SPARC64
441 TCGv carry = tcg_temp_new();
442 tcg_gen_extu_i32_tl(carry, carry_32);
443 tcg_gen_add_tl(dst, dst, carry);
444#else
445 tcg_gen_add_i32(dst, dst, carry_32);
446#endif
70c48285 447
420a187d
RH
448 if (update_cc) {
449 tcg_debug_assert(dst == cpu_cc_dst);
450 tcg_gen_mov_tl(cpu_cc_src, src1);
451 tcg_gen_mov_tl(cpu_cc_src2, src2);
452 }
453}
70c48285 454
420a187d
RH
455static void gen_op_addc_int_add(TCGv dst, TCGv src1, TCGv src2, bool update_cc)
456{
457 TCGv discard;
70c48285 458
420a187d
RH
459 if (TARGET_LONG_BITS == 64) {
460 gen_op_addc_int(dst, src1, src2, gen_add32_carry32(), update_cc);
461 return;
70c48285
RH
462 }
463
420a187d
RH
464 /*
465 * We can re-use the host's hardware carry generation by using
466 * an ADD2 opcode. We discard the low part of the output.
467 * Ideally we'd combine this operation with the add that
468 * generated the carry in the first place.
469 */
470 discard = tcg_temp_new();
471 tcg_gen_add2_tl(discard, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
70c48285 472
70c48285 473 if (update_cc) {
420a187d 474 tcg_debug_assert(dst == cpu_cc_dst);
70c48285
RH
475 tcg_gen_mov_tl(cpu_cc_src, src1);
476 tcg_gen_mov_tl(cpu_cc_src2, src2);
70c48285 477 }
dc99a3f2
BS
478}
479
420a187d
RH
480static void gen_op_addc_add(TCGv dst, TCGv src1, TCGv src2)
481{
482 gen_op_addc_int_add(dst, src1, src2, false);
483}
484
485static void gen_op_addccc_add(TCGv dst, TCGv src1, TCGv src2)
486{
487 gen_op_addc_int_add(dst, src1, src2, true);
488}
489
490static void gen_op_addc_sub(TCGv dst, TCGv src1, TCGv src2)
491{
492 gen_op_addc_int(dst, src1, src2, gen_sub32_carry32(), false);
493}
494
495static void gen_op_addccc_sub(TCGv dst, TCGv src1, TCGv src2)
496{
497 gen_op_addc_int(dst, src1, src2, gen_sub32_carry32(), true);
498}
499
500static void gen_op_addc_int_generic(TCGv dst, TCGv src1, TCGv src2,
501 bool update_cc)
502{
503 TCGv_i32 carry_32 = tcg_temp_new_i32();
504 gen_helper_compute_C_icc(carry_32, tcg_env);
505 gen_op_addc_int(dst, src1, src2, carry_32, update_cc);
506}
507
508static void gen_op_addc_generic(TCGv dst, TCGv src1, TCGv src2)
509{
510 gen_op_addc_int_generic(dst, src1, src2, false);
511}
512
513static void gen_op_addccc_generic(TCGv dst, TCGv src1, TCGv src2)
514{
515 gen_op_addc_int_generic(dst, src1, src2, true);
516}
517
0c2e96c1 518static void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
dc99a3f2 519{
4af984a7 520 tcg_gen_mov_tl(cpu_cc_src, src1);
6f551262 521 tcg_gen_mov_tl(cpu_cc_src2, src2);
41d72852 522 tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
d4b0d468 523 tcg_gen_mov_tl(dst, cpu_cc_dst);
41d72852
BS
524}
525
dfebb950
RH
526static void gen_op_subc_int(TCGv dst, TCGv src1, TCGv src2,
527 TCGv_i32 carry_32, bool update_cc)
41d72852 528{
70c48285 529 TCGv carry;
41d72852 530
70c48285
RH
531#if TARGET_LONG_BITS == 64
532 carry = tcg_temp_new();
533 tcg_gen_extu_i32_i64(carry, carry_32);
534#else
535 carry = carry_32;
536#endif
537
538 tcg_gen_sub_tl(dst, src1, src2);
539 tcg_gen_sub_tl(dst, dst, carry);
540
70c48285 541 if (update_cc) {
dfebb950 542 tcg_debug_assert(dst == cpu_cc_dst);
70c48285
RH
543 tcg_gen_mov_tl(cpu_cc_src, src1);
544 tcg_gen_mov_tl(cpu_cc_src2, src2);
70c48285 545 }
dc99a3f2
BS
546}
547
dfebb950
RH
548static void gen_op_subc_add(TCGv dst, TCGv src1, TCGv src2)
549{
550 gen_op_subc_int(dst, src1, src2, gen_add32_carry32(), false);
551}
552
553static void gen_op_subccc_add(TCGv dst, TCGv src1, TCGv src2)
554{
555 gen_op_subc_int(dst, src1, src2, gen_add32_carry32(), true);
556}
557
558static void gen_op_subc_int_sub(TCGv dst, TCGv src1, TCGv src2, bool update_cc)
559{
560 TCGv discard;
561
562 if (TARGET_LONG_BITS == 64) {
563 gen_op_subc_int(dst, src1, src2, gen_sub32_carry32(), update_cc);
564 return;
565 }
566
567 /*
568 * We can re-use the host's hardware carry generation by using
569 * a SUB2 opcode. We discard the low part of the output.
570 */
571 discard = tcg_temp_new();
572 tcg_gen_sub2_tl(discard, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
573
574 if (update_cc) {
575 tcg_debug_assert(dst == cpu_cc_dst);
576 tcg_gen_mov_tl(cpu_cc_src, src1);
577 tcg_gen_mov_tl(cpu_cc_src2, src2);
578 }
579}
580
581static void gen_op_subc_sub(TCGv dst, TCGv src1, TCGv src2)
582{
583 gen_op_subc_int_sub(dst, src1, src2, false);
584}
585
586static void gen_op_subccc_sub(TCGv dst, TCGv src1, TCGv src2)
587{
588 gen_op_subc_int_sub(dst, src1, src2, true);
589}
590
591static void gen_op_subc_int_generic(TCGv dst, TCGv src1, TCGv src2,
592 bool update_cc)
593{
594 TCGv_i32 carry_32 = tcg_temp_new_i32();
595
596 gen_helper_compute_C_icc(carry_32, tcg_env);
597 gen_op_subc_int(dst, src1, src2, carry_32, update_cc);
598}
599
600static void gen_op_subc_generic(TCGv dst, TCGv src1, TCGv src2)
601{
602 gen_op_subc_int_generic(dst, src1, src2, false);
603}
604
605static void gen_op_subccc_generic(TCGv dst, TCGv src1, TCGv src2)
606{
607 gen_op_subc_int_generic(dst, src1, src2, true);
608}
609
0c2e96c1 610static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
d9bdab86 611{
de9e9d9f 612 TCGv r_temp, zero, t0;
d9bdab86 613
a7812ae4 614 r_temp = tcg_temp_new();
de9e9d9f 615 t0 = tcg_temp_new();
d9bdab86
BS
616
617 /* old op:
618 if (!(env->y & 1))
619 T1 = 0;
620 */
00ab7e61 621 zero = tcg_constant_tl(0);
72ccba79 622 tcg_gen_andi_tl(cpu_cc_src, src1, 0xffffffff);
255e1fcb 623 tcg_gen_andi_tl(r_temp, cpu_y, 0x1);
72ccba79 624 tcg_gen_andi_tl(cpu_cc_src2, src2, 0xffffffff);
6cb675b0
RH
625 tcg_gen_movcond_tl(TCG_COND_EQ, cpu_cc_src2, r_temp, zero,
626 zero, cpu_cc_src2);
d9bdab86
BS
627
628 // b2 = T0 & 1;
629 // env->y = (b2 << 31) | (env->y >> 1);
0b1183e3 630 tcg_gen_extract_tl(t0, cpu_y, 1, 31);
08d64e0d 631 tcg_gen_deposit_tl(cpu_y, t0, cpu_cc_src, 31, 1);
d9bdab86
BS
632
633 // b1 = N ^ V;
2a1905c7 634 tcg_gen_xor_tl(t0, cpu_cc_N, cpu_cc_V);
d9bdab86
BS
635
636 // T0 = (b1 << 31) | (T0 >> 1);
637 // src1 = T0;
2a1905c7 638 tcg_gen_andi_tl(t0, t0, 1u << 31);
6f551262 639 tcg_gen_shri_tl(cpu_cc_src, cpu_cc_src, 1);
de9e9d9f 640 tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
d9bdab86 641
5c6a0628 642 tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
d9bdab86 643
5c6a0628 644 tcg_gen_mov_tl(dst, cpu_cc_dst);
d9bdab86
BS
645}
646
0c2e96c1 647static void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext)
8879d139 648{
528692a8 649#if TARGET_LONG_BITS == 32
fb170183 650 if (sign_ext) {
528692a8 651 tcg_gen_muls2_tl(dst, cpu_y, src1, src2);
fb170183 652 } else {
528692a8 653 tcg_gen_mulu2_tl(dst, cpu_y, src1, src2);
fb170183 654 }
528692a8
RH
655#else
656 TCGv t0 = tcg_temp_new_i64();
657 TCGv t1 = tcg_temp_new_i64();
fb170183 658
528692a8
RH
659 if (sign_ext) {
660 tcg_gen_ext32s_i64(t0, src1);
661 tcg_gen_ext32s_i64(t1, src2);
662 } else {
663 tcg_gen_ext32u_i64(t0, src1);
664 tcg_gen_ext32u_i64(t1, src2);
665 }
fb170183 666
528692a8 667 tcg_gen_mul_i64(dst, t0, t1);
528692a8
RH
668 tcg_gen_shri_i64(cpu_y, dst, 32);
669#endif
8879d139
BS
670}
671
0c2e96c1 672static void gen_op_umul(TCGv dst, TCGv src1, TCGv src2)
8879d139 673{
fb170183
IK
674 /* zero-extend truncated operands before multiplication */
675 gen_op_multiply(dst, src1, src2, 0);
676}
8879d139 677
0c2e96c1 678static void gen_op_smul(TCGv dst, TCGv src1, TCGv src2)
fb170183
IK
679{
680 /* sign-extend truncated operands before multiplication */
681 gen_op_multiply(dst, src1, src2, 1);
8879d139
BS
682}
683
4ee85ea9
RH
684static void gen_op_udivx(TCGv dst, TCGv src1, TCGv src2)
685{
686 gen_helper_udivx(dst, tcg_env, src1, src2);
687}
688
689static void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2)
690{
691 gen_helper_sdivx(dst, tcg_env, src1, src2);
692}
693
c2636853
RH
694static void gen_op_udiv(TCGv dst, TCGv src1, TCGv src2)
695{
13260103 696#ifdef TARGET_SPARC64
c2636853 697 gen_helper_udiv(dst, tcg_env, src1, src2);
13260103
RH
698 tcg_gen_ext32u_tl(dst, dst);
699#else
700 TCGv_i64 t64 = tcg_temp_new_i64();
701 gen_helper_udiv(t64, tcg_env, src1, src2);
702 tcg_gen_trunc_i64_tl(dst, t64);
703#endif
c2636853
RH
704}
705
706static void gen_op_sdiv(TCGv dst, TCGv src1, TCGv src2)
707{
13260103 708#ifdef TARGET_SPARC64
c2636853 709 gen_helper_sdiv(dst, tcg_env, src1, src2);
13260103
RH
710 tcg_gen_ext32s_tl(dst, dst);
711#else
712 TCGv_i64 t64 = tcg_temp_new_i64();
713 gen_helper_sdiv(t64, tcg_env, src1, src2);
714 tcg_gen_trunc_i64_tl(dst, t64);
715#endif
c2636853
RH
716}
717
718static void gen_op_udivcc(TCGv dst, TCGv src1, TCGv src2)
719{
13260103
RH
720 TCGv_i64 t64;
721
722#ifdef TARGET_SPARC64
723 t64 = cpu_cc_V;
724#else
725 t64 = tcg_temp_new_i64();
726#endif
727
728 gen_helper_udiv(t64, tcg_env, src1, src2);
729
730#ifdef TARGET_SPARC64
731 tcg_gen_ext32u_tl(cpu_cc_N, t64);
732 tcg_gen_shri_tl(cpu_cc_V, t64, 32);
733 tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
734 tcg_gen_movi_tl(cpu_icc_C, 0);
735#else
736 tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64);
737#endif
738 tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
739 tcg_gen_movi_tl(cpu_cc_C, 0);
740 tcg_gen_mov_tl(dst, cpu_cc_N);
c2636853
RH
741}
742
743static void gen_op_sdivcc(TCGv dst, TCGv src1, TCGv src2)
744{
13260103
RH
745 TCGv_i64 t64;
746
747#ifdef TARGET_SPARC64
748 t64 = cpu_cc_V;
749#else
750 t64 = tcg_temp_new_i64();
751#endif
752
753 gen_helper_sdiv(t64, tcg_env, src1, src2);
754
755#ifdef TARGET_SPARC64
756 tcg_gen_ext32s_tl(cpu_cc_N, t64);
757 tcg_gen_shri_tl(cpu_cc_V, t64, 32);
758 tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
759 tcg_gen_movi_tl(cpu_icc_C, 0);
760#else
761 tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64);
762#endif
763 tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
764 tcg_gen_movi_tl(cpu_cc_C, 0);
765 tcg_gen_mov_tl(dst, cpu_cc_N);
c2636853
RH
766}
767
a9aba13d
RH
768static void gen_op_taddcctv(TCGv dst, TCGv src1, TCGv src2)
769{
770 gen_helper_taddcctv(dst, tcg_env, src1, src2);
771}
772
773static void gen_op_tsubcctv(TCGv dst, TCGv src1, TCGv src2)
774{
775 gen_helper_tsubcctv(dst, tcg_env, src1, src2);
776}
777
9c6ec5bc
RH
778static void gen_op_popc(TCGv dst, TCGv src1, TCGv src2)
779{
780 tcg_gen_ctpop_tl(dst, src2);
781}
782
45bfed3b
RH
783#ifndef TARGET_SPARC64
784static void gen_helper_array8(TCGv dst, TCGv src1, TCGv src2)
785{
786 g_assert_not_reached();
787}
788#endif
789
790static void gen_op_array16(TCGv dst, TCGv src1, TCGv src2)
791{
792 gen_helper_array8(dst, src1, src2);
793 tcg_gen_shli_tl(dst, dst, 1);
794}
795
796static void gen_op_array32(TCGv dst, TCGv src1, TCGv src2)
797{
798 gen_helper_array8(dst, src1, src2);
799 tcg_gen_shli_tl(dst, dst, 2);
800}
801
2f722641
RH
802static void gen_op_fpack16(TCGv_i32 dst, TCGv_i64 src)
803{
804#ifdef TARGET_SPARC64
805 gen_helper_fpack16(dst, cpu_gsr, src);
806#else
807 g_assert_not_reached();
808#endif
809}
810
811static void gen_op_fpackfix(TCGv_i32 dst, TCGv_i64 src)
812{
813#ifdef TARGET_SPARC64
814 gen_helper_fpackfix(dst, cpu_gsr, src);
815#else
816 g_assert_not_reached();
817#endif
818}
819
4b6edc0a
RH
820static void gen_op_fpack32(TCGv_i64 dst, TCGv_i64 src1, TCGv_i64 src2)
821{
822#ifdef TARGET_SPARC64
823 gen_helper_fpack32(dst, cpu_gsr, src1, src2);
824#else
825 g_assert_not_reached();
826#endif
827}
828
829static void gen_op_faligndata(TCGv_i64 dst, TCGv_i64 s1, TCGv_i64 s2)
830{
831#ifdef TARGET_SPARC64
832 TCGv t1, t2, shift;
833
834 t1 = tcg_temp_new();
835 t2 = tcg_temp_new();
836 shift = tcg_temp_new();
837
838 tcg_gen_andi_tl(shift, cpu_gsr, 7);
839 tcg_gen_shli_tl(shift, shift, 3);
840 tcg_gen_shl_tl(t1, s1, shift);
841
842 /*
843 * A shift of 64 does not produce 0 in TCG. Divide this into a
844 * shift of (up to 63) followed by a constant shift of 1.
845 */
846 tcg_gen_xori_tl(shift, shift, 63);
847 tcg_gen_shr_tl(t2, s2, shift);
848 tcg_gen_shri_tl(t2, t2, 1);
849
850 tcg_gen_or_tl(dst, t1, t2);
851#else
852 g_assert_not_reached();
853#endif
854}
855
856static void gen_op_bshuffle(TCGv_i64 dst, TCGv_i64 src1, TCGv_i64 src2)
857{
858#ifdef TARGET_SPARC64
859 gen_helper_bshuffle(dst, cpu_gsr, src1, src2);
860#else
861 g_assert_not_reached();
862#endif
863}
864
19f329ad 865// 1
0c2e96c1 866static void gen_op_eval_ba(TCGv dst)
19f329ad
BS
867{
868 tcg_gen_movi_tl(dst, 1);
869}
870
19f329ad 871// 0
0c2e96c1 872static void gen_op_eval_bn(TCGv dst)
19f329ad
BS
873{
874 tcg_gen_movi_tl(dst, 0);
875}
876
19f329ad
BS
877/*
878 FPSR bit field FCC1 | FCC0:
879 0 =
880 1 <
881 2 >
882 3 unordered
883*/
0c2e96c1 884static void gen_mov_reg_FCC0(TCGv reg, TCGv src,
19f329ad
BS
885 unsigned int fcc_offset)
886{
ba6a9d8c 887 tcg_gen_shri_tl(reg, src, FSR_FCC0_SHIFT + fcc_offset);
19f329ad
BS
888 tcg_gen_andi_tl(reg, reg, 0x1);
889}
890
0c2e96c1 891static void gen_mov_reg_FCC1(TCGv reg, TCGv src, unsigned int fcc_offset)
19f329ad 892{
ba6a9d8c 893 tcg_gen_shri_tl(reg, src, FSR_FCC1_SHIFT + fcc_offset);
19f329ad
BS
894 tcg_gen_andi_tl(reg, reg, 0x1);
895}
896
897// !0: FCC0 | FCC1
0c2e96c1 898static void gen_op_eval_fbne(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 899{
de9e9d9f 900 TCGv t0 = tcg_temp_new();
19f329ad 901 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
902 gen_mov_reg_FCC1(t0, src, fcc_offset);
903 tcg_gen_or_tl(dst, dst, t0);
19f329ad
BS
904}
905
906// 1 or 2: FCC0 ^ FCC1
0c2e96c1 907static void gen_op_eval_fblg(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 908{
de9e9d9f 909 TCGv t0 = tcg_temp_new();
19f329ad 910 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
911 gen_mov_reg_FCC1(t0, src, fcc_offset);
912 tcg_gen_xor_tl(dst, dst, t0);
19f329ad
BS
913}
914
915// 1 or 3: FCC0
0c2e96c1 916static void gen_op_eval_fbul(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad
BS
917{
918 gen_mov_reg_FCC0(dst, src, fcc_offset);
919}
920
921// 1: FCC0 & !FCC1
0c2e96c1 922static void gen_op_eval_fbl(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 923{
de9e9d9f 924 TCGv t0 = tcg_temp_new();
19f329ad 925 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
926 gen_mov_reg_FCC1(t0, src, fcc_offset);
927 tcg_gen_andc_tl(dst, dst, t0);
19f329ad
BS
928}
929
930// 2 or 3: FCC1
0c2e96c1 931static void gen_op_eval_fbug(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad
BS
932{
933 gen_mov_reg_FCC1(dst, src, fcc_offset);
934}
935
936// 2: !FCC0 & FCC1
0c2e96c1 937static void gen_op_eval_fbg(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 938{
de9e9d9f 939 TCGv t0 = tcg_temp_new();
19f329ad 940 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
941 gen_mov_reg_FCC1(t0, src, fcc_offset);
942 tcg_gen_andc_tl(dst, t0, dst);
19f329ad
BS
943}
944
945// 3: FCC0 & FCC1
0c2e96c1 946static void gen_op_eval_fbu(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 947{
de9e9d9f 948 TCGv t0 = tcg_temp_new();
19f329ad 949 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
950 gen_mov_reg_FCC1(t0, src, fcc_offset);
951 tcg_gen_and_tl(dst, dst, t0);
19f329ad
BS
952}
953
954// 0: !(FCC0 | FCC1)
0c2e96c1 955static void gen_op_eval_fbe(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 956{
de9e9d9f 957 TCGv t0 = tcg_temp_new();
19f329ad 958 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
959 gen_mov_reg_FCC1(t0, src, fcc_offset);
960 tcg_gen_or_tl(dst, dst, t0);
19f329ad
BS
961 tcg_gen_xori_tl(dst, dst, 0x1);
962}
963
964// 0 or 3: !(FCC0 ^ FCC1)
0c2e96c1 965static void gen_op_eval_fbue(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 966{
de9e9d9f 967 TCGv t0 = tcg_temp_new();
19f329ad 968 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
969 gen_mov_reg_FCC1(t0, src, fcc_offset);
970 tcg_gen_xor_tl(dst, dst, t0);
19f329ad
BS
971 tcg_gen_xori_tl(dst, dst, 0x1);
972}
973
974// 0 or 2: !FCC0
0c2e96c1 975static void gen_op_eval_fbge(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad
BS
976{
977 gen_mov_reg_FCC0(dst, src, fcc_offset);
978 tcg_gen_xori_tl(dst, dst, 0x1);
979}
980
981// !1: !(FCC0 & !FCC1)
0c2e96c1 982static void gen_op_eval_fbuge(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 983{
de9e9d9f 984 TCGv t0 = tcg_temp_new();
19f329ad 985 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
986 gen_mov_reg_FCC1(t0, src, fcc_offset);
987 tcg_gen_andc_tl(dst, dst, t0);
19f329ad
BS
988 tcg_gen_xori_tl(dst, dst, 0x1);
989}
990
991// 0 or 1: !FCC1
0c2e96c1 992static void gen_op_eval_fble(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad
BS
993{
994 gen_mov_reg_FCC1(dst, src, fcc_offset);
995 tcg_gen_xori_tl(dst, dst, 0x1);
996}
997
998// !2: !(!FCC0 & FCC1)
0c2e96c1 999static void gen_op_eval_fbule(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 1000{
de9e9d9f 1001 TCGv t0 = tcg_temp_new();
19f329ad 1002 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
1003 gen_mov_reg_FCC1(t0, src, fcc_offset);
1004 tcg_gen_andc_tl(dst, t0, dst);
19f329ad 1005 tcg_gen_xori_tl(dst, dst, 0x1);
19f329ad
BS
1006}
1007
1008// !3: !(FCC0 & FCC1)
0c2e96c1 1009static void gen_op_eval_fbo(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 1010{
de9e9d9f 1011 TCGv t0 = tcg_temp_new();
19f329ad 1012 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
1013 gen_mov_reg_FCC1(t0, src, fcc_offset);
1014 tcg_gen_and_tl(dst, dst, t0);
19f329ad
BS
1015 tcg_gen_xori_tl(dst, dst, 0x1);
1016}
1017
0c2e96c1
RH
1018static void gen_branch2(DisasContext *dc, target_ulong pc1,
1019 target_ulong pc2, TCGv r_cond)
83469015 1020{
42a268c2 1021 TCGLabel *l1 = gen_new_label();
83469015 1022
cb63669a 1023 tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
83469015 1024
6e256c93 1025 gen_goto_tb(dc, 0, pc1, pc1 + 4);
83469015
FB
1026
1027 gen_set_label(l1);
6e256c93 1028 gen_goto_tb(dc, 1, pc2, pc2 + 4);
83469015
FB
1029}
1030
0c2e96c1 1031static void gen_generic_branch(DisasContext *dc)
83469015 1032{
00ab7e61
RH
1033 TCGv npc0 = tcg_constant_tl(dc->jump_pc[0]);
1034 TCGv npc1 = tcg_constant_tl(dc->jump_pc[1]);
1035 TCGv zero = tcg_constant_tl(0);
19f329ad 1036
61316742 1037 tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, zero, npc0, npc1);
83469015
FB
1038}
1039
4af984a7
BS
1040/* call this function before using the condition register as it may
1041 have been set for a jump */
0c2e96c1 1042static void flush_cond(DisasContext *dc)
83469015
FB
1043{
1044 if (dc->npc == JUMP_PC) {
2e655fe7 1045 gen_generic_branch(dc);
99c82c47 1046 dc->npc = DYNAMIC_PC_LOOKUP;
83469015
FB
1047 }
1048}
1049
0c2e96c1 1050static void save_npc(DisasContext *dc)
72cbca10 1051{
633c4283
RH
1052 if (dc->npc & 3) {
1053 switch (dc->npc) {
1054 case JUMP_PC:
1055 gen_generic_branch(dc);
99c82c47 1056 dc->npc = DYNAMIC_PC_LOOKUP;
633c4283
RH
1057 break;
1058 case DYNAMIC_PC:
1059 case DYNAMIC_PC_LOOKUP:
1060 break;
1061 default:
1062 g_assert_not_reached();
1063 }
1064 } else {
2f5680ee 1065 tcg_gen_movi_tl(cpu_npc, dc->npc);
72cbca10
FB
1066 }
1067}
1068
0c2e96c1 1069static void update_psr(DisasContext *dc)
72cbca10 1070{
cfa90513
BS
1071 if (dc->cc_op != CC_OP_FLAGS) {
1072 dc->cc_op = CC_OP_FLAGS;
ad75a51e 1073 gen_helper_compute_psr(tcg_env);
cfa90513 1074 }
20132b96
RH
1075}
1076
0c2e96c1 1077static void save_state(DisasContext *dc)
20132b96
RH
1078{
1079 tcg_gen_movi_tl(cpu_pc, dc->pc);
934da7ee 1080 save_npc(dc);
72cbca10
FB
1081}
1082
4fbe0067
RH
1083static void gen_exception(DisasContext *dc, int which)
1084{
4fbe0067 1085 save_state(dc);
ad75a51e 1086 gen_helper_raise_exception(tcg_env, tcg_constant_i32(which));
af00be49 1087 dc->base.is_jmp = DISAS_NORETURN;
4fbe0067
RH
1088}
1089
186e7890 1090static TCGLabel *delay_exceptionv(DisasContext *dc, TCGv_i32 excp)
35e94905 1091{
186e7890
RH
1092 DisasDelayException *e = g_new0(DisasDelayException, 1);
1093
1094 e->next = dc->delay_excp_list;
1095 dc->delay_excp_list = e;
1096
1097 e->lab = gen_new_label();
1098 e->excp = excp;
1099 e->pc = dc->pc;
1100 /* Caller must have used flush_cond before branch. */
1101 assert(e->npc != JUMP_PC);
1102 e->npc = dc->npc;
1103
1104 return e->lab;
1105}
1106
1107static TCGLabel *delay_exception(DisasContext *dc, int excp)
1108{
1109 return delay_exceptionv(dc, tcg_constant_i32(excp));
1110}
1111
1112static void gen_check_align(DisasContext *dc, TCGv addr, int mask)
1113{
1114 TCGv t = tcg_temp_new();
1115 TCGLabel *lab;
1116
1117 tcg_gen_andi_tl(t, addr, mask);
1118
1119 flush_cond(dc);
1120 lab = delay_exception(dc, TT_UNALIGNED);
1121 tcg_gen_brcondi_tl(TCG_COND_NE, t, 0, lab);
35e94905
RH
1122}
1123
0c2e96c1 1124static void gen_mov_pc_npc(DisasContext *dc)
0bee699e 1125{
633c4283
RH
1126 if (dc->npc & 3) {
1127 switch (dc->npc) {
1128 case JUMP_PC:
1129 gen_generic_branch(dc);
1130 tcg_gen_mov_tl(cpu_pc, cpu_npc);
99c82c47 1131 dc->pc = DYNAMIC_PC_LOOKUP;
633c4283
RH
1132 break;
1133 case DYNAMIC_PC:
1134 case DYNAMIC_PC_LOOKUP:
1135 tcg_gen_mov_tl(cpu_pc, cpu_npc);
1136 dc->pc = dc->npc;
1137 break;
1138 default:
1139 g_assert_not_reached();
1140 }
0bee699e
FB
1141 } else {
1142 dc->pc = dc->npc;
1143 }
1144}
1145
0c2e96c1 1146static void gen_op_next_insn(void)
38bc628b 1147{
48d5c82b
BS
1148 tcg_gen_mov_tl(cpu_pc, cpu_npc);
1149 tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
38bc628b
BS
1150}
1151
2a484ecf 1152static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
416fcaea 1153 DisasContext *dc)
19f329ad 1154{
2a484ecf 1155 static int subcc_cond[16] = {
96b5a3d3 1156 TCG_COND_NEVER,
2a484ecf
RH
1157 TCG_COND_EQ,
1158 TCG_COND_LE,
1159 TCG_COND_LT,
1160 TCG_COND_LEU,
1161 TCG_COND_LTU,
1162 -1, /* neg */
1163 -1, /* overflow */
96b5a3d3 1164 TCG_COND_ALWAYS,
2a484ecf
RH
1165 TCG_COND_NE,
1166 TCG_COND_GT,
1167 TCG_COND_GE,
1168 TCG_COND_GTU,
1169 TCG_COND_GEU,
1170 -1, /* pos */
1171 -1, /* no overflow */
1172 };
1173
2a1905c7 1174 TCGv t1, t2;
416fcaea 1175
2a1905c7 1176 cmp->is_bool = false;
2a484ecf 1177
8393617c 1178 switch (dc->cc_op) {
2a484ecf
RH
1179 case CC_OP_SUB:
1180 switch (cond) {
1181 case 6: /* neg */
1182 case 14: /* pos */
1183 cmp->cond = (cond == 6 ? TCG_COND_LT : TCG_COND_GE);
2a45b736
RH
1184 cmp->c2 = tcg_constant_tl(0);
1185 if (TARGET_LONG_BITS == 32 || xcc) {
1186 cmp->c1 = cpu_cc_dst;
1187 } else {
1188 cmp->c1 = t1 = tcg_temp_new();
1189 tcg_gen_ext32s_tl(t1, cpu_cc_dst);
1190 }
1191 return;
2a484ecf 1192
2a484ecf
RH
1193 case 7: /* overflow */
1194 case 15: /* !overflow */
2a1905c7 1195 break;
2a484ecf
RH
1196
1197 default:
1198 cmp->cond = subcc_cond[cond];
2a1905c7
RH
1199 if (TARGET_LONG_BITS == 32 || xcc) {
1200 cmp->c1 = cpu_cc_src;
1201 cmp->c2 = cpu_cc_src2;
1202 } else {
2a484ecf
RH
1203 /* Note that sign-extension works for unsigned compares as
1204 long as both operands are sign-extended. */
2a1905c7
RH
1205 cmp->c1 = t1 = tcg_temp_new();
1206 tcg_gen_ext32s_tl(t1, cpu_cc_src);
1207 cmp->c2 = t2 = tcg_temp_new();
1208 tcg_gen_ext32s_tl(t2, cpu_cc_src2);
2a484ecf 1209 }
2a1905c7 1210 return;
2a484ecf 1211 }
8393617c 1212 break;
2a484ecf 1213
8393617c 1214 default:
ad75a51e 1215 gen_helper_compute_psr(tcg_env);
8393617c 1216 dc->cc_op = CC_OP_FLAGS;
2a1905c7 1217 break;
2a484ecf
RH
1218
1219 case CC_OP_FLAGS:
2a1905c7
RH
1220 break;
1221 }
1222
1223 cmp->c1 = t1 = tcg_temp_new();
1224 cmp->c2 = tcg_constant_tl(0);
1225
1226 switch (cond & 7) {
1227 case 0x0: /* never */
1228 cmp->cond = TCG_COND_NEVER;
1229 cmp->c1 = cmp->c2;
1230 break;
1231
1232 case 0x1: /* eq: Z */
1233 cmp->cond = TCG_COND_EQ;
1234 if (TARGET_LONG_BITS == 32 || xcc) {
1235 tcg_gen_mov_tl(t1, cpu_cc_Z);
1236 } else {
1237 tcg_gen_ext32u_tl(t1, cpu_icc_Z);
1238 }
1239 break;
1240
1241 case 0x2: /* le: Z | (N ^ V) */
1242 /*
1243 * Simplify:
1244 * cc_Z || (N ^ V) < 0 NE
1245 * cc_Z && !((N ^ V) < 0) EQ
1246 * cc_Z & ~((N ^ V) >> TLB) EQ
1247 */
1248 cmp->cond = TCG_COND_EQ;
1249 tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V);
1250 tcg_gen_sextract_tl(t1, t1, xcc ? 63 : 31, 1);
1251 tcg_gen_andc_tl(t1, xcc ? cpu_cc_Z : cpu_icc_Z, t1);
1252 if (TARGET_LONG_BITS == 64 && !xcc) {
1253 tcg_gen_ext32u_tl(t1, t1);
1254 }
1255 break;
1256
1257 case 0x3: /* lt: N ^ V */
1258 cmp->cond = TCG_COND_LT;
1259 tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V);
1260 if (TARGET_LONG_BITS == 64 && !xcc) {
1261 tcg_gen_ext32s_tl(t1, t1);
1262 }
1263 break;
1264
1265 case 0x4: /* leu: Z | C */
1266 /*
1267 * Simplify:
1268 * cc_Z == 0 || cc_C != 0 NE
1269 * cc_Z != 0 && cc_C == 0 EQ
1270 * cc_Z & (cc_C ? 0 : -1) EQ
1271 * cc_Z & (cc_C - 1) EQ
1272 */
1273 cmp->cond = TCG_COND_EQ;
1274 if (TARGET_LONG_BITS == 32 || xcc) {
1275 tcg_gen_subi_tl(t1, cpu_cc_C, 1);
1276 tcg_gen_and_tl(t1, t1, cpu_cc_Z);
1277 } else {
1278 tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1);
1279 tcg_gen_subi_tl(t1, t1, 1);
1280 tcg_gen_and_tl(t1, t1, cpu_icc_Z);
1281 tcg_gen_ext32u_tl(t1, t1);
1282 }
1283 break;
1284
1285 case 0x5: /* ltu: C */
2a484ecf
RH
1286 cmp->cond = TCG_COND_NE;
1287 cmp->is_bool = true;
2a1905c7
RH
1288 if (TARGET_LONG_BITS == 32 || xcc) {
1289 tcg_gen_mov_tl(t1, cpu_cc_C);
1290 } else {
1291 tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1);
1292 }
1293 break;
2a484ecf 1294
2a1905c7
RH
1295 case 0x6: /* neg: N */
1296 cmp->cond = TCG_COND_LT;
1297 if (TARGET_LONG_BITS == 32 || xcc) {
1298 tcg_gen_mov_tl(t1, cpu_cc_N);
1299 } else {
1300 tcg_gen_ext32s_tl(t1, cpu_cc_N);
2a484ecf 1301 }
19f329ad 1302 break;
2a1905c7
RH
1303
1304 case 0x7: /* vs: V */
1305 cmp->cond = TCG_COND_LT;
1306 if (TARGET_LONG_BITS == 32 || xcc) {
1307 tcg_gen_mov_tl(t1, cpu_cc_V);
1308 } else {
1309 tcg_gen_ext32s_tl(t1, cpu_cc_V);
1310 }
1311 break;
1312 }
1313 if (cond & 8) {
1314 cmp->cond = tcg_invert_cond(cmp->cond);
1315 cmp->is_bool = false;
19f329ad
BS
1316 }
1317}
7a3f1944 1318
416fcaea 1319static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond)
e8af50a3 1320{
19f329ad 1321 unsigned int offset;
416fcaea
RH
1322 TCGv r_dst;
1323
1324 /* For now we still generate a straight boolean result. */
1325 cmp->cond = TCG_COND_NE;
1326 cmp->is_bool = true;
416fcaea 1327 cmp->c1 = r_dst = tcg_temp_new();
00ab7e61 1328 cmp->c2 = tcg_constant_tl(0);
19f329ad 1329
19f329ad
BS
1330 switch (cc) {
1331 default:
1332 case 0x0:
1333 offset = 0;
1334 break;
1335 case 0x1:
1336 offset = 32 - 10;
1337 break;
1338 case 0x2:
1339 offset = 34 - 10;
1340 break;
1341 case 0x3:
1342 offset = 36 - 10;
1343 break;
1344 }
1345
1346 switch (cond) {
1347 case 0x0:
1348 gen_op_eval_bn(r_dst);
1349 break;
1350 case 0x1:
87e92502 1351 gen_op_eval_fbne(r_dst, cpu_fsr, offset);
19f329ad
BS
1352 break;
1353 case 0x2:
87e92502 1354 gen_op_eval_fblg(r_dst, cpu_fsr, offset);
19f329ad
BS
1355 break;
1356 case 0x3:
87e92502 1357 gen_op_eval_fbul(r_dst, cpu_fsr, offset);
19f329ad
BS
1358 break;
1359 case 0x4:
87e92502 1360 gen_op_eval_fbl(r_dst, cpu_fsr, offset);
19f329ad
BS
1361 break;
1362 case 0x5:
87e92502 1363 gen_op_eval_fbug(r_dst, cpu_fsr, offset);
19f329ad
BS
1364 break;
1365 case 0x6:
87e92502 1366 gen_op_eval_fbg(r_dst, cpu_fsr, offset);
19f329ad
BS
1367 break;
1368 case 0x7:
87e92502 1369 gen_op_eval_fbu(r_dst, cpu_fsr, offset);
19f329ad
BS
1370 break;
1371 case 0x8:
1372 gen_op_eval_ba(r_dst);
1373 break;
1374 case 0x9:
87e92502 1375 gen_op_eval_fbe(r_dst, cpu_fsr, offset);
19f329ad
BS
1376 break;
1377 case 0xa:
87e92502 1378 gen_op_eval_fbue(r_dst, cpu_fsr, offset);
19f329ad
BS
1379 break;
1380 case 0xb:
87e92502 1381 gen_op_eval_fbge(r_dst, cpu_fsr, offset);
19f329ad
BS
1382 break;
1383 case 0xc:
87e92502 1384 gen_op_eval_fbuge(r_dst, cpu_fsr, offset);
19f329ad
BS
1385 break;
1386 case 0xd:
87e92502 1387 gen_op_eval_fble(r_dst, cpu_fsr, offset);
19f329ad
BS
1388 break;
1389 case 0xe:
87e92502 1390 gen_op_eval_fbule(r_dst, cpu_fsr, offset);
19f329ad
BS
1391 break;
1392 case 0xf:
87e92502 1393 gen_op_eval_fbo(r_dst, cpu_fsr, offset);
19f329ad
BS
1394 break;
1395 }
e8af50a3 1396}
00f219bf
BS
1397
1398// Inverted logic
ab9ffe98
RH
1399static const TCGCond gen_tcg_cond_reg[8] = {
1400 TCG_COND_NEVER, /* reserved */
00f219bf
BS
1401 TCG_COND_NE,
1402 TCG_COND_GT,
1403 TCG_COND_GE,
ab9ffe98 1404 TCG_COND_NEVER, /* reserved */
00f219bf
BS
1405 TCG_COND_EQ,
1406 TCG_COND_LE,
1407 TCG_COND_LT,
1408};
19f329ad 1409
416fcaea
RH
1410static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src)
1411{
1412 cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]);
1413 cmp->is_bool = false;
416fcaea 1414 cmp->c1 = r_src;
00ab7e61 1415 cmp->c2 = tcg_constant_tl(0);
416fcaea
RH
1416}
1417
baf3dbf2
RH
1418static void gen_op_clear_ieee_excp_and_FTT(void)
1419{
1420 tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK);
1421}
1422
1423static void gen_op_fmovs(TCGv_i32 dst, TCGv_i32 src)
1424{
1425 gen_op_clear_ieee_excp_and_FTT();
1426 tcg_gen_mov_i32(dst, src);
1427}
1428
1429static void gen_op_fnegs(TCGv_i32 dst, TCGv_i32 src)
1430{
1431 gen_op_clear_ieee_excp_and_FTT();
1432 gen_helper_fnegs(dst, src);
1433}
1434
1435static void gen_op_fabss(TCGv_i32 dst, TCGv_i32 src)
1436{
1437 gen_op_clear_ieee_excp_and_FTT();
1438 gen_helper_fabss(dst, src);
1439}
1440
c6d83e4f
RH
1441static void gen_op_fmovd(TCGv_i64 dst, TCGv_i64 src)
1442{
1443 gen_op_clear_ieee_excp_and_FTT();
1444 tcg_gen_mov_i64(dst, src);
1445}
1446
1447static void gen_op_fnegd(TCGv_i64 dst, TCGv_i64 src)
1448{
1449 gen_op_clear_ieee_excp_and_FTT();
1450 gen_helper_fnegd(dst, src);
1451}
1452
1453static void gen_op_fabsd(TCGv_i64 dst, TCGv_i64 src)
1454{
1455 gen_op_clear_ieee_excp_and_FTT();
1456 gen_helper_fabsd(dst, src);
1457}
1458
3475187d 1459#ifdef TARGET_SPARC64
0c2e96c1 1460static void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
7e8c2b6c 1461{
714547bb
BS
1462 switch (fccno) {
1463 case 0:
ad75a51e 1464 gen_helper_fcmps(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1465 break;
1466 case 1:
ad75a51e 1467 gen_helper_fcmps_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1468 break;
1469 case 2:
ad75a51e 1470 gen_helper_fcmps_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1471 break;
1472 case 3:
ad75a51e 1473 gen_helper_fcmps_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1474 break;
1475 }
7e8c2b6c
BS
1476}
1477
0c2e96c1 1478static void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
7e8c2b6c 1479{
a7812ae4
PB
1480 switch (fccno) {
1481 case 0:
ad75a51e 1482 gen_helper_fcmpd(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1483 break;
1484 case 1:
ad75a51e 1485 gen_helper_fcmpd_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1486 break;
1487 case 2:
ad75a51e 1488 gen_helper_fcmpd_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1489 break;
1490 case 3:
ad75a51e 1491 gen_helper_fcmpd_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1492 break;
1493 }
7e8c2b6c
BS
1494}
1495
0c2e96c1 1496static void gen_op_fcmpq(int fccno)
7e8c2b6c 1497{
a7812ae4
PB
1498 switch (fccno) {
1499 case 0:
ad75a51e 1500 gen_helper_fcmpq(cpu_fsr, tcg_env);
a7812ae4
PB
1501 break;
1502 case 1:
ad75a51e 1503 gen_helper_fcmpq_fcc1(cpu_fsr, tcg_env);
a7812ae4
PB
1504 break;
1505 case 2:
ad75a51e 1506 gen_helper_fcmpq_fcc2(cpu_fsr, tcg_env);
a7812ae4
PB
1507 break;
1508 case 3:
ad75a51e 1509 gen_helper_fcmpq_fcc3(cpu_fsr, tcg_env);
a7812ae4
PB
1510 break;
1511 }
7e8c2b6c 1512}
7e8c2b6c 1513
0c2e96c1 1514static void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
7e8c2b6c 1515{
714547bb
BS
1516 switch (fccno) {
1517 case 0:
ad75a51e 1518 gen_helper_fcmpes(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1519 break;
1520 case 1:
ad75a51e 1521 gen_helper_fcmpes_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1522 break;
1523 case 2:
ad75a51e 1524 gen_helper_fcmpes_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1525 break;
1526 case 3:
ad75a51e 1527 gen_helper_fcmpes_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1528 break;
1529 }
7e8c2b6c
BS
1530}
1531
0c2e96c1 1532static void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
7e8c2b6c 1533{
a7812ae4
PB
1534 switch (fccno) {
1535 case 0:
ad75a51e 1536 gen_helper_fcmped(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1537 break;
1538 case 1:
ad75a51e 1539 gen_helper_fcmped_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1540 break;
1541 case 2:
ad75a51e 1542 gen_helper_fcmped_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1543 break;
1544 case 3:
ad75a51e 1545 gen_helper_fcmped_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1546 break;
1547 }
7e8c2b6c
BS
1548}
1549
0c2e96c1 1550static void gen_op_fcmpeq(int fccno)
7e8c2b6c 1551{
a7812ae4
PB
1552 switch (fccno) {
1553 case 0:
ad75a51e 1554 gen_helper_fcmpeq(cpu_fsr, tcg_env);
a7812ae4
PB
1555 break;
1556 case 1:
ad75a51e 1557 gen_helper_fcmpeq_fcc1(cpu_fsr, tcg_env);
a7812ae4
PB
1558 break;
1559 case 2:
ad75a51e 1560 gen_helper_fcmpeq_fcc2(cpu_fsr, tcg_env);
a7812ae4
PB
1561 break;
1562 case 3:
ad75a51e 1563 gen_helper_fcmpeq_fcc3(cpu_fsr, tcg_env);
a7812ae4
PB
1564 break;
1565 }
7e8c2b6c 1566}
7e8c2b6c
BS
1567
1568#else
1569
0c2e96c1 1570static void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
7e8c2b6c 1571{
ad75a51e 1572 gen_helper_fcmps(cpu_fsr, tcg_env, r_rs1, r_rs2);
7e8c2b6c
BS
1573}
1574
0c2e96c1 1575static void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
7e8c2b6c 1576{
ad75a51e 1577 gen_helper_fcmpd(cpu_fsr, tcg_env, r_rs1, r_rs2);
7e8c2b6c
BS
1578}
1579
0c2e96c1 1580static void gen_op_fcmpq(int fccno)
7e8c2b6c 1581{
ad75a51e 1582 gen_helper_fcmpq(cpu_fsr, tcg_env);
7e8c2b6c 1583}
7e8c2b6c 1584
0c2e96c1 1585static void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
7e8c2b6c 1586{
ad75a51e 1587 gen_helper_fcmpes(cpu_fsr, tcg_env, r_rs1, r_rs2);
7e8c2b6c
BS
1588}
1589
0c2e96c1 1590static void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
7e8c2b6c 1591{
ad75a51e 1592 gen_helper_fcmped(cpu_fsr, tcg_env, r_rs1, r_rs2);
7e8c2b6c
BS
1593}
1594
0c2e96c1 1595static void gen_op_fcmpeq(int fccno)
7e8c2b6c 1596{
ad75a51e 1597 gen_helper_fcmpeq(cpu_fsr, tcg_env);
7e8c2b6c
BS
1598}
1599#endif
1600
4fbe0067 1601static void gen_op_fpexception_im(DisasContext *dc, int fsr_flags)
134d77a1 1602{
47ad35f1 1603 tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
87e92502 1604 tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
4fbe0067 1605 gen_exception(dc, TT_FP_EXCP);
134d77a1
BS
1606}
1607
5b12f1e8 1608static int gen_trap_ifnofpu(DisasContext *dc)
a80dde08
FB
1609{
1610#if !defined(CONFIG_USER_ONLY)
1611 if (!dc->fpu_enabled) {
4fbe0067 1612 gen_exception(dc, TT_NFPU_INSN);
a80dde08
FB
1613 return 1;
1614 }
1615#endif
1616 return 0;
1617}
1618
1a2fb1c0 1619/* asi moves */
7ec1e5ea
RH
1620typedef enum {
1621 GET_ASI_HELPER,
1622 GET_ASI_EXCP,
f0913be0 1623 GET_ASI_DIRECT,
e4dc0052 1624 GET_ASI_DTWINX,
ca5ce572
RH
1625 GET_ASI_BLOCK,
1626 GET_ASI_SHORT,
34810610
RH
1627 GET_ASI_BCOPY,
1628 GET_ASI_BFILL,
7ec1e5ea
RH
1629} ASIType;
1630
1631typedef struct {
1632 ASIType type;
a6d567e5 1633 int asi;
f0913be0 1634 int mem_idx;
14776ab5 1635 MemOp memop;
7ec1e5ea 1636} DisasASI;
1a2fb1c0 1637
811cc0b0
RH
1638/*
1639 * Build DisasASI.
1640 * For asi == -1, treat as non-asi.
1641 * For ask == -2, treat as immediate offset (v8 error, v9 %asi).
1642 */
1643static DisasASI resolve_asi(DisasContext *dc, int asi, MemOp memop)
7ec1e5ea 1644{
7ec1e5ea 1645 ASIType type = GET_ASI_HELPER;
f0913be0 1646 int mem_idx = dc->mem_idx;
7ec1e5ea 1647
811cc0b0
RH
1648 if (asi == -1) {
1649 /* Artificial "non-asi" case. */
1650 type = GET_ASI_DIRECT;
1651 goto done;
1652 }
1653
7ec1e5ea
RH
1654#ifndef TARGET_SPARC64
1655 /* Before v9, all asis are immediate and privileged. */
811cc0b0 1656 if (asi < 0) {
22e70060 1657 gen_exception(dc, TT_ILL_INSN);
7ec1e5ea
RH
1658 type = GET_ASI_EXCP;
1659 } else if (supervisor(dc)
1660 /* Note that LEON accepts ASI_USERDATA in user mode, for
1661 use with CASA. Also note that previous versions of
0cc1f4bf
RH
1662 QEMU allowed (and old versions of gcc emitted) ASI_P
1663 for LEON, which is incorrect. */
1664 || (asi == ASI_USERDATA
7ec1e5ea 1665 && (dc->def->features & CPU_FEATURE_CASA))) {
f0913be0
RH
1666 switch (asi) {
1667 case ASI_USERDATA: /* User data access */
1668 mem_idx = MMU_USER_IDX;
1669 type = GET_ASI_DIRECT;
1670 break;
1671 case ASI_KERNELDATA: /* Supervisor data access */
1672 mem_idx = MMU_KERNEL_IDX;
1673 type = GET_ASI_DIRECT;
1674 break;
7f87c905
RH
1675 case ASI_M_BYPASS: /* MMU passthrough */
1676 case ASI_LEON_BYPASS: /* LEON MMU passthrough */
1677 mem_idx = MMU_PHYS_IDX;
1678 type = GET_ASI_DIRECT;
1679 break;
34810610
RH
1680 case ASI_M_BCOPY: /* Block copy, sta access */
1681 mem_idx = MMU_KERNEL_IDX;
1682 type = GET_ASI_BCOPY;
1683 break;
1684 case ASI_M_BFILL: /* Block fill, stda access */
1685 mem_idx = MMU_KERNEL_IDX;
1686 type = GET_ASI_BFILL;
1687 break;
f0913be0 1688 }
6e10f37c
KF
1689
1690 /* MMU_PHYS_IDX is used when the MMU is disabled to passthrough the
1691 * permissions check in get_physical_address(..).
1692 */
1693 mem_idx = (dc->mem_idx == MMU_PHYS_IDX) ? MMU_PHYS_IDX : mem_idx;
1a2fb1c0 1694 } else {
7ec1e5ea
RH
1695 gen_exception(dc, TT_PRIV_INSN);
1696 type = GET_ASI_EXCP;
1697 }
1698#else
811cc0b0 1699 if (asi < 0) {
7ec1e5ea 1700 asi = dc->asi;
1a2fb1c0 1701 }
f0913be0
RH
1702 /* With v9, all asis below 0x80 are privileged. */
1703 /* ??? We ought to check cpu_has_hypervisor, but we didn't copy
1704 down that bit into DisasContext. For the moment that's ok,
1705 since the direct implementations below doesn't have any ASIs
1706 in the restricted [0x30, 0x7f] range, and the check will be
1707 done properly in the helper. */
1708 if (!supervisor(dc) && asi < 0x80) {
1709 gen_exception(dc, TT_PRIV_ACT);
1710 type = GET_ASI_EXCP;
1711 } else {
1712 switch (asi) {
7f87c905
RH
1713 case ASI_REAL: /* Bypass */
1714 case ASI_REAL_IO: /* Bypass, non-cacheable */
1715 case ASI_REAL_L: /* Bypass LE */
1716 case ASI_REAL_IO_L: /* Bypass, non-cacheable LE */
1717 case ASI_TWINX_REAL: /* Real address, twinx */
1718 case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
34a6e13d
RH
1719 case ASI_QUAD_LDD_PHYS:
1720 case ASI_QUAD_LDD_PHYS_L:
7f87c905
RH
1721 mem_idx = MMU_PHYS_IDX;
1722 break;
f0913be0
RH
1723 case ASI_N: /* Nucleus */
1724 case ASI_NL: /* Nucleus LE */
e4dc0052
RH
1725 case ASI_TWINX_N:
1726 case ASI_TWINX_NL:
34a6e13d
RH
1727 case ASI_NUCLEUS_QUAD_LDD:
1728 case ASI_NUCLEUS_QUAD_LDD_L:
9a10756d 1729 if (hypervisor(dc)) {
84f8f587 1730 mem_idx = MMU_PHYS_IDX;
9a10756d
AT
1731 } else {
1732 mem_idx = MMU_NUCLEUS_IDX;
1733 }
f0913be0
RH
1734 break;
1735 case ASI_AIUP: /* As if user primary */
1736 case ASI_AIUPL: /* As if user primary LE */
e4dc0052
RH
1737 case ASI_TWINX_AIUP:
1738 case ASI_TWINX_AIUP_L:
ca5ce572
RH
1739 case ASI_BLK_AIUP_4V:
1740 case ASI_BLK_AIUP_L_4V:
1741 case ASI_BLK_AIUP:
1742 case ASI_BLK_AIUPL:
f0913be0
RH
1743 mem_idx = MMU_USER_IDX;
1744 break;
1745 case ASI_AIUS: /* As if user secondary */
1746 case ASI_AIUSL: /* As if user secondary LE */
e4dc0052
RH
1747 case ASI_TWINX_AIUS:
1748 case ASI_TWINX_AIUS_L:
ca5ce572
RH
1749 case ASI_BLK_AIUS_4V:
1750 case ASI_BLK_AIUS_L_4V:
1751 case ASI_BLK_AIUS:
1752 case ASI_BLK_AIUSL:
f0913be0
RH
1753 mem_idx = MMU_USER_SECONDARY_IDX;
1754 break;
1755 case ASI_S: /* Secondary */
1756 case ASI_SL: /* Secondary LE */
e4dc0052
RH
1757 case ASI_TWINX_S:
1758 case ASI_TWINX_SL:
ca5ce572
RH
1759 case ASI_BLK_COMMIT_S:
1760 case ASI_BLK_S:
1761 case ASI_BLK_SL:
1762 case ASI_FL8_S:
1763 case ASI_FL8_SL:
1764 case ASI_FL16_S:
1765 case ASI_FL16_SL:
f0913be0
RH
1766 if (mem_idx == MMU_USER_IDX) {
1767 mem_idx = MMU_USER_SECONDARY_IDX;
1768 } else if (mem_idx == MMU_KERNEL_IDX) {
1769 mem_idx = MMU_KERNEL_SECONDARY_IDX;
1770 }
1771 break;
1772 case ASI_P: /* Primary */
1773 case ASI_PL: /* Primary LE */
e4dc0052
RH
1774 case ASI_TWINX_P:
1775 case ASI_TWINX_PL:
ca5ce572
RH
1776 case ASI_BLK_COMMIT_P:
1777 case ASI_BLK_P:
1778 case ASI_BLK_PL:
1779 case ASI_FL8_P:
1780 case ASI_FL8_PL:
1781 case ASI_FL16_P:
1782 case ASI_FL16_PL:
f0913be0
RH
1783 break;
1784 }
1785 switch (asi) {
7f87c905
RH
1786 case ASI_REAL:
1787 case ASI_REAL_IO:
1788 case ASI_REAL_L:
1789 case ASI_REAL_IO_L:
f0913be0
RH
1790 case ASI_N:
1791 case ASI_NL:
1792 case ASI_AIUP:
1793 case ASI_AIUPL:
1794 case ASI_AIUS:
1795 case ASI_AIUSL:
1796 case ASI_S:
1797 case ASI_SL:
1798 case ASI_P:
1799 case ASI_PL:
1800 type = GET_ASI_DIRECT;
1801 break;
7f87c905
RH
1802 case ASI_TWINX_REAL:
1803 case ASI_TWINX_REAL_L:
e4dc0052
RH
1804 case ASI_TWINX_N:
1805 case ASI_TWINX_NL:
1806 case ASI_TWINX_AIUP:
1807 case ASI_TWINX_AIUP_L:
1808 case ASI_TWINX_AIUS:
1809 case ASI_TWINX_AIUS_L:
1810 case ASI_TWINX_P:
1811 case ASI_TWINX_PL:
1812 case ASI_TWINX_S:
1813 case ASI_TWINX_SL:
34a6e13d
RH
1814 case ASI_QUAD_LDD_PHYS:
1815 case ASI_QUAD_LDD_PHYS_L:
1816 case ASI_NUCLEUS_QUAD_LDD:
1817 case ASI_NUCLEUS_QUAD_LDD_L:
e4dc0052
RH
1818 type = GET_ASI_DTWINX;
1819 break;
ca5ce572
RH
1820 case ASI_BLK_COMMIT_P:
1821 case ASI_BLK_COMMIT_S:
1822 case ASI_BLK_AIUP_4V:
1823 case ASI_BLK_AIUP_L_4V:
1824 case ASI_BLK_AIUP:
1825 case ASI_BLK_AIUPL:
1826 case ASI_BLK_AIUS_4V:
1827 case ASI_BLK_AIUS_L_4V:
1828 case ASI_BLK_AIUS:
1829 case ASI_BLK_AIUSL:
1830 case ASI_BLK_S:
1831 case ASI_BLK_SL:
1832 case ASI_BLK_P:
1833 case ASI_BLK_PL:
1834 type = GET_ASI_BLOCK;
1835 break;
1836 case ASI_FL8_S:
1837 case ASI_FL8_SL:
1838 case ASI_FL8_P:
1839 case ASI_FL8_PL:
1840 memop = MO_UB;
1841 type = GET_ASI_SHORT;
1842 break;
1843 case ASI_FL16_S:
1844 case ASI_FL16_SL:
1845 case ASI_FL16_P:
1846 case ASI_FL16_PL:
1847 memop = MO_TEUW;
1848 type = GET_ASI_SHORT;
1849 break;
f0913be0
RH
1850 }
1851 /* The little-endian asis all have bit 3 set. */
1852 if (asi & 8) {
1853 memop ^= MO_BSWAP;
1854 }
1855 }
7ec1e5ea
RH
1856#endif
1857
811cc0b0 1858 done:
f0913be0 1859 return (DisasASI){ type, asi, mem_idx, memop };
0425bee5
BS
1860}
1861
a76779ee
RH
1862#if defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
1863static void gen_helper_ld_asi(TCGv_i64 r, TCGv_env e, TCGv a,
1864 TCGv_i32 asi, TCGv_i32 mop)
1865{
1866 g_assert_not_reached();
1867}
1868
1869static void gen_helper_st_asi(TCGv_env e, TCGv a, TCGv_i64 r,
1870 TCGv_i32 asi, TCGv_i32 mop)
1871{
1872 g_assert_not_reached();
1873}
1874#endif
1875
42071fc1 1876static void gen_ld_asi(DisasContext *dc, DisasASI *da, TCGv dst, TCGv addr)
0425bee5 1877{
c03a0fd1 1878 switch (da->type) {
7ec1e5ea
RH
1879 case GET_ASI_EXCP:
1880 break;
e4dc0052
RH
1881 case GET_ASI_DTWINX: /* Reserved for ldda. */
1882 gen_exception(dc, TT_ILL_INSN);
1883 break;
f0913be0 1884 case GET_ASI_DIRECT:
c03a0fd1 1885 tcg_gen_qemu_ld_tl(dst, addr, da->mem_idx, da->memop | MO_ALIGN);
f0913be0 1886 break;
7ec1e5ea
RH
1887 default:
1888 {
c03a0fd1
RH
1889 TCGv_i32 r_asi = tcg_constant_i32(da->asi);
1890 TCGv_i32 r_mop = tcg_constant_i32(da->memop | MO_ALIGN);
7ec1e5ea
RH
1891
1892 save_state(dc);
22e70060 1893#ifdef TARGET_SPARC64
ad75a51e 1894 gen_helper_ld_asi(dst, tcg_env, addr, r_asi, r_mop);
22e70060 1895#else
7ec1e5ea
RH
1896 {
1897 TCGv_i64 t64 = tcg_temp_new_i64();
ad75a51e 1898 gen_helper_ld_asi(t64, tcg_env, addr, r_asi, r_mop);
7ec1e5ea 1899 tcg_gen_trunc_i64_tl(dst, t64);
7ec1e5ea 1900 }
22e70060 1901#endif
7ec1e5ea
RH
1902 }
1903 break;
1904 }
1a2fb1c0
BS
1905}
1906
42071fc1 1907static void gen_st_asi(DisasContext *dc, DisasASI *da, TCGv src, TCGv addr)
c03a0fd1
RH
1908{
1909 switch (da->type) {
7ec1e5ea
RH
1910 case GET_ASI_EXCP:
1911 break;
c03a0fd1 1912
e4dc0052 1913 case GET_ASI_DTWINX: /* Reserved for stda. */
c03a0fd1
RH
1914 if (TARGET_LONG_BITS == 32) {
1915 gen_exception(dc, TT_ILL_INSN);
1916 break;
1917 } else if (!(dc->def->features & CPU_FEATURE_HYPV)) {
3390537b
AT
1918 /* Pre OpenSPARC CPUs don't have these */
1919 gen_exception(dc, TT_ILL_INSN);
c03a0fd1 1920 break;
3390537b 1921 }
c03a0fd1 1922 /* In OpenSPARC T1+ CPUs TWINX ASIs in store are ST_BLKINIT_ ASIs */
fc0cd867 1923 /* fall through */
c03a0fd1 1924
f0913be0 1925 case GET_ASI_DIRECT:
c03a0fd1 1926 tcg_gen_qemu_st_tl(src, addr, da->mem_idx, da->memop | MO_ALIGN);
f0913be0 1927 break;
c03a0fd1 1928
34810610 1929 case GET_ASI_BCOPY:
c03a0fd1 1930 assert(TARGET_LONG_BITS == 32);
34810610
RH
1931 /* Copy 32 bytes from the address in SRC to ADDR. */
1932 /* ??? The original qemu code suggests 4-byte alignment, dropping
1933 the low bits, but the only place I can see this used is in the
1934 Linux kernel with 32 byte alignment, which would make more sense
1935 as a cacheline-style operation. */
1936 {
1937 TCGv saddr = tcg_temp_new();
1938 TCGv daddr = tcg_temp_new();
00ab7e61 1939 TCGv four = tcg_constant_tl(4);
34810610
RH
1940 TCGv_i32 tmp = tcg_temp_new_i32();
1941 int i;
1942
1943 tcg_gen_andi_tl(saddr, src, -4);
1944 tcg_gen_andi_tl(daddr, addr, -4);
1945 for (i = 0; i < 32; i += 4) {
1946 /* Since the loads and stores are paired, allow the
1947 copy to happen in the host endianness. */
c03a0fd1
RH
1948 tcg_gen_qemu_ld_i32(tmp, saddr, da->mem_idx, MO_UL);
1949 tcg_gen_qemu_st_i32(tmp, daddr, da->mem_idx, MO_UL);
34810610
RH
1950 tcg_gen_add_tl(saddr, saddr, four);
1951 tcg_gen_add_tl(daddr, daddr, four);
1952 }
34810610
RH
1953 }
1954 break;
c03a0fd1 1955
7ec1e5ea
RH
1956 default:
1957 {
c03a0fd1
RH
1958 TCGv_i32 r_asi = tcg_constant_i32(da->asi);
1959 TCGv_i32 r_mop = tcg_constant_i32(da->memop | MO_ALIGN);
7ec1e5ea
RH
1960
1961 save_state(dc);
22e70060 1962#ifdef TARGET_SPARC64
ad75a51e 1963 gen_helper_st_asi(tcg_env, addr, src, r_asi, r_mop);
22e70060 1964#else
7ec1e5ea
RH
1965 {
1966 TCGv_i64 t64 = tcg_temp_new_i64();
1967 tcg_gen_extu_tl_i64(t64, src);
ad75a51e 1968 gen_helper_st_asi(tcg_env, addr, t64, r_asi, r_mop);
7ec1e5ea 1969 }
22e70060 1970#endif
7ec1e5ea
RH
1971
1972 /* A write to a TLB register may alter page maps. End the TB. */
1973 dc->npc = DYNAMIC_PC;
1974 }
1975 break;
1976 }
1a2fb1c0
BS
1977}
1978
dca544b9
RH
1979static void gen_swap_asi(DisasContext *dc, DisasASI *da,
1980 TCGv dst, TCGv src, TCGv addr)
c03a0fd1
RH
1981{
1982 switch (da->type) {
7ec1e5ea
RH
1983 case GET_ASI_EXCP:
1984 break;
4fb554bc 1985 case GET_ASI_DIRECT:
dca544b9
RH
1986 tcg_gen_atomic_xchg_tl(dst, addr, src,
1987 da->mem_idx, da->memop | MO_ALIGN);
4fb554bc 1988 break;
7ec1e5ea 1989 default:
4fb554bc
RH
1990 /* ??? Should be DAE_invalid_asi. */
1991 gen_exception(dc, TT_DATA_ACCESS);
7ec1e5ea
RH
1992 break;
1993 }
1a2fb1c0
BS
1994}
1995
d0a11d25
RH
1996static void gen_cas_asi(DisasContext *dc, DisasASI *da,
1997 TCGv oldv, TCGv newv, TCGv cmpv, TCGv addr)
c03a0fd1
RH
1998{
1999 switch (da->type) {
7268adeb 2000 case GET_ASI_EXCP:
7ec1e5ea 2001 return;
7268adeb 2002 case GET_ASI_DIRECT:
c03a0fd1
RH
2003 tcg_gen_atomic_cmpxchg_tl(oldv, addr, cmpv, newv,
2004 da->mem_idx, da->memop | MO_ALIGN);
7268adeb
RH
2005 break;
2006 default:
2007 /* ??? Should be DAE_invalid_asi. */
2008 gen_exception(dc, TT_DATA_ACCESS);
2009 break;
7ec1e5ea 2010 }
22e70060
RH
2011}
2012
cf07cd1e 2013static void gen_ldstub_asi(DisasContext *dc, DisasASI *da, TCGv dst, TCGv addr)
c03a0fd1
RH
2014{
2015 switch (da->type) {
7ec1e5ea
RH
2016 case GET_ASI_EXCP:
2017 break;
fbb4bbb6 2018 case GET_ASI_DIRECT:
cf07cd1e
RH
2019 tcg_gen_atomic_xchg_tl(dst, addr, tcg_constant_tl(0xff),
2020 da->mem_idx, MO_UB);
fbb4bbb6 2021 break;
7ec1e5ea 2022 default:
3db010c3
RH
2023 /* ??? In theory, this should be raise DAE_invalid_asi.
2024 But the SS-20 roms do ldstuba [%l0] #ASI_M_CTL, %o1. */
af00be49 2025 if (tb_cflags(dc->base.tb) & CF_PARALLEL) {
ad75a51e 2026 gen_helper_exit_atomic(tcg_env);
3db010c3 2027 } else {
c03a0fd1 2028 TCGv_i32 r_asi = tcg_constant_i32(da->asi);
00ab7e61 2029 TCGv_i32 r_mop = tcg_constant_i32(MO_UB);
3db010c3
RH
2030 TCGv_i64 s64, t64;
2031
2032 save_state(dc);
2033 t64 = tcg_temp_new_i64();
ad75a51e 2034 gen_helper_ld_asi(t64, tcg_env, addr, r_asi, r_mop);
3db010c3 2035
00ab7e61 2036 s64 = tcg_constant_i64(0xff);
ad75a51e 2037 gen_helper_st_asi(tcg_env, addr, s64, r_asi, r_mop);
3db010c3
RH
2038
2039 tcg_gen_trunc_i64_tl(dst, t64);
3db010c3
RH
2040
2041 /* End the TB. */
2042 dc->npc = DYNAMIC_PC;
2043 }
7ec1e5ea
RH
2044 break;
2045 }
22e70060 2046}
22e70060 2047
287b1152
RH
2048static void gen_ldf_asi(DisasContext *dc, DisasASI *da, MemOp orig_size,
2049 TCGv addr, int rd)
1a2fb1c0 2050{
3259b9e2
RH
2051 MemOp memop = da->memop;
2052 MemOp size = memop & MO_SIZE;
7705091c 2053 TCGv_i32 d32;
cb21b4da 2054 TCGv_i64 d64;
287b1152 2055 TCGv addr_tmp;
1a2fb1c0 2056
3259b9e2
RH
2057 /* TODO: Use 128-bit load/store below. */
2058 if (size == MO_128) {
2059 memop = (memop & ~MO_SIZE) | MO_64;
2060 }
2061
2062 switch (da->type) {
7ec1e5ea
RH
2063 case GET_ASI_EXCP:
2064 break;
7705091c
RH
2065
2066 case GET_ASI_DIRECT:
3259b9e2 2067 memop |= MO_ALIGN_4;
7705091c 2068 switch (size) {
3259b9e2 2069 case MO_32:
7705091c 2070 d32 = gen_dest_fpr_F(dc);
3259b9e2 2071 tcg_gen_qemu_ld_i32(d32, addr, da->mem_idx, memop);
7705091c
RH
2072 gen_store_fpr_F(dc, rd, d32);
2073 break;
3259b9e2
RH
2074
2075 case MO_64:
2076 tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da->mem_idx, memop);
7705091c 2077 break;
3259b9e2
RH
2078
2079 case MO_128:
cb21b4da 2080 d64 = tcg_temp_new_i64();
3259b9e2 2081 tcg_gen_qemu_ld_i64(d64, addr, da->mem_idx, memop);
287b1152
RH
2082 addr_tmp = tcg_temp_new();
2083 tcg_gen_addi_tl(addr_tmp, addr, 8);
2084 tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + 1], addr_tmp, da->mem_idx, memop);
cb21b4da 2085 tcg_gen_mov_i64(cpu_fpr[rd / 2], d64);
7705091c
RH
2086 break;
2087 default:
2088 g_assert_not_reached();
2089 }
2090 break;
2091
ca5ce572
RH
2092 case GET_ASI_BLOCK:
2093 /* Valid for lddfa on aligned registers only. */
3259b9e2 2094 if (orig_size == MO_64 && (rd & 7) == 0) {
80883227 2095 /* The first operation checks required alignment. */
287b1152
RH
2096 addr_tmp = tcg_temp_new();
2097 for (int i = 0; ; ++i) {
3259b9e2
RH
2098 tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + i], addr, da->mem_idx,
2099 memop | (i == 0 ? MO_ALIGN_64 : 0));
ca5ce572
RH
2100 if (i == 7) {
2101 break;
2102 }
287b1152
RH
2103 tcg_gen_addi_tl(addr_tmp, addr, 8);
2104 addr = addr_tmp;
ca5ce572 2105 }
ca5ce572
RH
2106 } else {
2107 gen_exception(dc, TT_ILL_INSN);
2108 }
2109 break;
2110
2111 case GET_ASI_SHORT:
2112 /* Valid for lddfa only. */
3259b9e2
RH
2113 if (orig_size == MO_64) {
2114 tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da->mem_idx,
2115 memop | MO_ALIGN);
ca5ce572
RH
2116 } else {
2117 gen_exception(dc, TT_ILL_INSN);
2118 }
2119 break;
2120
7ec1e5ea
RH
2121 default:
2122 {
3259b9e2
RH
2123 TCGv_i32 r_asi = tcg_constant_i32(da->asi);
2124 TCGv_i32 r_mop = tcg_constant_i32(memop | MO_ALIGN);
7ec1e5ea
RH
2125
2126 save_state(dc);
f2fe396f
RH
2127 /* According to the table in the UA2011 manual, the only
2128 other asis that are valid for ldfa/lddfa/ldqfa are
2129 the NO_FAULT asis. We still need a helper for these,
2130 but we can just use the integer asi helper for them. */
2131 switch (size) {
3259b9e2 2132 case MO_32:
cb21b4da 2133 d64 = tcg_temp_new_i64();
ad75a51e 2134 gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop);
cb21b4da
RH
2135 d32 = gen_dest_fpr_F(dc);
2136 tcg_gen_extrl_i64_i32(d32, d64);
cb21b4da 2137 gen_store_fpr_F(dc, rd, d32);
f2fe396f 2138 break;
3259b9e2
RH
2139 case MO_64:
2140 gen_helper_ld_asi(cpu_fpr[rd / 2], tcg_env, addr,
2141 r_asi, r_mop);
f2fe396f 2142 break;
3259b9e2 2143 case MO_128:
cb21b4da 2144 d64 = tcg_temp_new_i64();
ad75a51e 2145 gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop);
287b1152
RH
2146 addr_tmp = tcg_temp_new();
2147 tcg_gen_addi_tl(addr_tmp, addr, 8);
2148 gen_helper_ld_asi(cpu_fpr[rd / 2 + 1], tcg_env, addr_tmp,
3259b9e2 2149 r_asi, r_mop);
cb21b4da 2150 tcg_gen_mov_i64(cpu_fpr[rd / 2], d64);
f2fe396f
RH
2151 break;
2152 default:
2153 g_assert_not_reached();
2154 }
7ec1e5ea
RH
2155 }
2156 break;
2157 }
1a2fb1c0
BS
2158}
2159
287b1152
RH
2160static void gen_stf_asi(DisasContext *dc, DisasASI *da, MemOp orig_size,
2161 TCGv addr, int rd)
3259b9e2
RH
2162{
2163 MemOp memop = da->memop;
2164 MemOp size = memop & MO_SIZE;
7705091c 2165 TCGv_i32 d32;
287b1152 2166 TCGv addr_tmp;
1a2fb1c0 2167
3259b9e2
RH
2168 /* TODO: Use 128-bit load/store below. */
2169 if (size == MO_128) {
2170 memop = (memop & ~MO_SIZE) | MO_64;
2171 }
2172
2173 switch (da->type) {
7ec1e5ea
RH
2174 case GET_ASI_EXCP:
2175 break;
7705091c
RH
2176
2177 case GET_ASI_DIRECT:
3259b9e2 2178 memop |= MO_ALIGN_4;
7705091c 2179 switch (size) {
3259b9e2 2180 case MO_32:
7705091c 2181 d32 = gen_load_fpr_F(dc, rd);
3259b9e2 2182 tcg_gen_qemu_st_i32(d32, addr, da->mem_idx, memop | MO_ALIGN);
7705091c 2183 break;
3259b9e2
RH
2184 case MO_64:
2185 tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx,
2186 memop | MO_ALIGN_4);
7705091c 2187 break;
3259b9e2 2188 case MO_128:
cb21b4da
RH
2189 /* Only 4-byte alignment required. However, it is legal for the
2190 cpu to signal the alignment fault, and the OS trap handler is
2191 required to fix it up. Requiring 16-byte alignment here avoids
2192 having to probe the second page before performing the first
2193 write. */
3259b9e2
RH
2194 tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx,
2195 memop | MO_ALIGN_16);
287b1152
RH
2196 addr_tmp = tcg_temp_new();
2197 tcg_gen_addi_tl(addr_tmp, addr, 8);
2198 tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + 1], addr_tmp, da->mem_idx, memop);
7705091c
RH
2199 break;
2200 default:
2201 g_assert_not_reached();
2202 }
2203 break;
2204
ca5ce572
RH
2205 case GET_ASI_BLOCK:
2206 /* Valid for stdfa on aligned registers only. */
3259b9e2 2207 if (orig_size == MO_64 && (rd & 7) == 0) {
80883227 2208 /* The first operation checks required alignment. */
287b1152
RH
2209 addr_tmp = tcg_temp_new();
2210 for (int i = 0; ; ++i) {
3259b9e2
RH
2211 tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + i], addr, da->mem_idx,
2212 memop | (i == 0 ? MO_ALIGN_64 : 0));
ca5ce572
RH
2213 if (i == 7) {
2214 break;
2215 }
287b1152
RH
2216 tcg_gen_addi_tl(addr_tmp, addr, 8);
2217 addr = addr_tmp;
ca5ce572 2218 }
ca5ce572
RH
2219 } else {
2220 gen_exception(dc, TT_ILL_INSN);
2221 }
2222 break;
2223
2224 case GET_ASI_SHORT:
2225 /* Valid for stdfa only. */
3259b9e2
RH
2226 if (orig_size == MO_64) {
2227 tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx,
2228 memop | MO_ALIGN);
ca5ce572
RH
2229 } else {
2230 gen_exception(dc, TT_ILL_INSN);
2231 }
2232 break;
2233
7ec1e5ea 2234 default:
f2fe396f
RH
2235 /* According to the table in the UA2011 manual, the only
2236 other asis that are valid for ldfa/lddfa/ldqfa are
2237 the PST* asis, which aren't currently handled. */
2238 gen_exception(dc, TT_ILL_INSN);
7ec1e5ea
RH
2239 break;
2240 }
1a2fb1c0
BS
2241}
2242
42071fc1 2243static void gen_ldda_asi(DisasContext *dc, DisasASI *da, TCGv addr, int rd)
1a2fb1c0 2244{
a76779ee
RH
2245 TCGv hi = gen_dest_gpr(dc, rd);
2246 TCGv lo = gen_dest_gpr(dc, rd + 1);
1a2fb1c0 2247
c03a0fd1 2248 switch (da->type) {
7ec1e5ea 2249 case GET_ASI_EXCP:
e4dc0052
RH
2250 return;
2251
2252 case GET_ASI_DTWINX:
ebbbec92
RH
2253#ifdef TARGET_SPARC64
2254 {
2255 MemOp mop = (da->memop & MO_BSWAP) | MO_128 | MO_ALIGN_16;
2256 TCGv_i128 t = tcg_temp_new_i128();
2257
2258 tcg_gen_qemu_ld_i128(t, addr, da->mem_idx, mop);
2259 /*
2260 * Note that LE twinx acts as if each 64-bit register result is
2261 * byte swapped. We perform one 128-bit LE load, so must swap
2262 * the order of the writebacks.
2263 */
2264 if ((mop & MO_BSWAP) == MO_TE) {
2265 tcg_gen_extr_i128_i64(lo, hi, t);
2266 } else {
2267 tcg_gen_extr_i128_i64(hi, lo, t);
2268 }
2269 }
7ec1e5ea 2270 break;
ebbbec92
RH
2271#else
2272 g_assert_not_reached();
2273#endif
e4dc0052
RH
2274
2275 case GET_ASI_DIRECT:
2276 {
2277 TCGv_i64 tmp = tcg_temp_new_i64();
2278
c03a0fd1 2279 tcg_gen_qemu_ld_i64(tmp, addr, da->mem_idx, da->memop | MO_ALIGN);
e4dc0052
RH
2280
2281 /* Note that LE ldda acts as if each 32-bit register
2282 result is byte swapped. Having just performed one
2283 64-bit bswap, we need now to swap the writebacks. */
c03a0fd1 2284 if ((da->memop & MO_BSWAP) == MO_TE) {
a76779ee 2285 tcg_gen_extr_i64_tl(lo, hi, tmp);
e4dc0052 2286 } else {
a76779ee 2287 tcg_gen_extr_i64_tl(hi, lo, tmp);
e4dc0052 2288 }
e4dc0052
RH
2289 }
2290 break;
2291
7ec1e5ea 2292 default:
918d9a2c
RH
2293 /* ??? In theory we've handled all of the ASIs that are valid
2294 for ldda, and this should raise DAE_invalid_asi. However,
2295 real hardware allows others. This can be seen with e.g.
2296 FreeBSD 10.3 wrt ASI_IC_TAG. */
7ec1e5ea 2297 {
c03a0fd1
RH
2298 TCGv_i32 r_asi = tcg_constant_i32(da->asi);
2299 TCGv_i32 r_mop = tcg_constant_i32(da->memop);
918d9a2c 2300 TCGv_i64 tmp = tcg_temp_new_i64();
7ec1e5ea
RH
2301
2302 save_state(dc);
ad75a51e 2303 gen_helper_ld_asi(tmp, tcg_env, addr, r_asi, r_mop);
3f4288eb 2304
918d9a2c 2305 /* See above. */
c03a0fd1 2306 if ((da->memop & MO_BSWAP) == MO_TE) {
a76779ee 2307 tcg_gen_extr_i64_tl(lo, hi, tmp);
918d9a2c 2308 } else {
a76779ee 2309 tcg_gen_extr_i64_tl(hi, lo, tmp);
918d9a2c 2310 }
7ec1e5ea
RH
2311 }
2312 break;
2313 }
e4dc0052
RH
2314
2315 gen_store_gpr(dc, rd, hi);
2316 gen_store_gpr(dc, rd + 1, lo);
0425bee5
BS
2317}
2318
42071fc1 2319static void gen_stda_asi(DisasContext *dc, DisasASI *da, TCGv addr, int rd)
c03a0fd1
RH
2320{
2321 TCGv hi = gen_load_gpr(dc, rd);
c7785e16 2322 TCGv lo = gen_load_gpr(dc, rd + 1);
a7ec4229 2323
c03a0fd1 2324 switch (da->type) {
7ec1e5ea
RH
2325 case GET_ASI_EXCP:
2326 break;
e4dc0052
RH
2327
2328 case GET_ASI_DTWINX:
ebbbec92
RH
2329#ifdef TARGET_SPARC64
2330 {
2331 MemOp mop = (da->memop & MO_BSWAP) | MO_128 | MO_ALIGN_16;
2332 TCGv_i128 t = tcg_temp_new_i128();
2333
2334 /*
2335 * Note that LE twinx acts as if each 64-bit register result is
2336 * byte swapped. We perform one 128-bit LE store, so must swap
2337 * the order of the construction.
2338 */
2339 if ((mop & MO_BSWAP) == MO_TE) {
2340 tcg_gen_concat_i64_i128(t, lo, hi);
2341 } else {
2342 tcg_gen_concat_i64_i128(t, hi, lo);
2343 }
2344 tcg_gen_qemu_st_i128(t, addr, da->mem_idx, mop);
2345 }
e4dc0052 2346 break;
ebbbec92
RH
2347#else
2348 g_assert_not_reached();
2349#endif
e4dc0052
RH
2350
2351 case GET_ASI_DIRECT:
2352 {
2353 TCGv_i64 t64 = tcg_temp_new_i64();
2354
2355 /* Note that LE stda acts as if each 32-bit register result is
2356 byte swapped. We will perform one 64-bit LE store, so now
2357 we must swap the order of the construction. */
c03a0fd1 2358 if ((da->memop & MO_BSWAP) == MO_TE) {
a76779ee 2359 tcg_gen_concat_tl_i64(t64, lo, hi);
e4dc0052 2360 } else {
a76779ee 2361 tcg_gen_concat_tl_i64(t64, hi, lo);
e4dc0052 2362 }
c03a0fd1 2363 tcg_gen_qemu_st_i64(t64, addr, da->mem_idx, da->memop | MO_ALIGN);
e4dc0052
RH
2364 }
2365 break;
2366
a76779ee
RH
2367 case GET_ASI_BFILL:
2368 assert(TARGET_LONG_BITS == 32);
2369 /* Store 32 bytes of T64 to ADDR. */
2370 /* ??? The original qemu code suggests 8-byte alignment, dropping
2371 the low bits, but the only place I can see this used is in the
2372 Linux kernel with 32 byte alignment, which would make more sense
2373 as a cacheline-style operation. */
2374 {
2375 TCGv_i64 t64 = tcg_temp_new_i64();
2376 TCGv d_addr = tcg_temp_new();
2377 TCGv eight = tcg_constant_tl(8);
2378 int i;
2379
2380 tcg_gen_concat_tl_i64(t64, lo, hi);
2381 tcg_gen_andi_tl(d_addr, addr, -8);
2382 for (i = 0; i < 32; i += 8) {
c03a0fd1 2383 tcg_gen_qemu_st_i64(t64, d_addr, da->mem_idx, da->memop);
a76779ee
RH
2384 tcg_gen_add_tl(d_addr, d_addr, eight);
2385 }
2386 }
2387 break;
2388
7ec1e5ea 2389 default:
918d9a2c
RH
2390 /* ??? In theory we've handled all of the ASIs that are valid
2391 for stda, and this should raise DAE_invalid_asi. */
7ec1e5ea 2392 {
c03a0fd1
RH
2393 TCGv_i32 r_asi = tcg_constant_i32(da->asi);
2394 TCGv_i32 r_mop = tcg_constant_i32(da->memop);
918d9a2c 2395 TCGv_i64 t64 = tcg_temp_new_i64();
7ec1e5ea 2396
918d9a2c 2397 /* See above. */
c03a0fd1 2398 if ((da->memop & MO_BSWAP) == MO_TE) {
a76779ee 2399 tcg_gen_concat_tl_i64(t64, lo, hi);
918d9a2c 2400 } else {
a76779ee 2401 tcg_gen_concat_tl_i64(t64, hi, lo);
918d9a2c 2402 }
7ec1e5ea 2403
918d9a2c 2404 save_state(dc);
ad75a51e 2405 gen_helper_st_asi(tcg_env, addr, t64, r_asi, r_mop);
7ec1e5ea
RH
2406 }
2407 break;
2408 }
1a2fb1c0
BS
2409}
2410
7e480893
RH
2411static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
2412{
f7ec8155 2413#ifdef TARGET_SPARC64
7e480893
RH
2414 TCGv_i32 c32, zero, dst, s1, s2;
2415
2416 /* We have two choices here: extend the 32 bit data and use movcond_i64,
2417 or fold the comparison down to 32 bits and use movcond_i32. Choose
2418 the later. */
2419 c32 = tcg_temp_new_i32();
2420 if (cmp->is_bool) {
ecc7b3aa 2421 tcg_gen_extrl_i64_i32(c32, cmp->c1);
7e480893
RH
2422 } else {
2423 TCGv_i64 c64 = tcg_temp_new_i64();
2424 tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2);
ecc7b3aa 2425 tcg_gen_extrl_i64_i32(c32, c64);
7e480893
RH
2426 }
2427
2428 s1 = gen_load_fpr_F(dc, rs);
2429 s2 = gen_load_fpr_F(dc, rd);
ba5f5179 2430 dst = gen_dest_fpr_F(dc);
00ab7e61 2431 zero = tcg_constant_i32(0);
7e480893
RH
2432
2433 tcg_gen_movcond_i32(TCG_COND_NE, dst, c32, zero, s1, s2);
2434
7e480893 2435 gen_store_fpr_F(dc, rd, dst);
f7ec8155
RH
2436#else
2437 qemu_build_not_reached();
2438#endif
7e480893
RH
2439}
2440
2441static void gen_fmovd(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
2442{
f7ec8155 2443#ifdef TARGET_SPARC64
3886b8a3 2444 TCGv_i64 dst = gen_dest_fpr_D(dc, rd);
7e480893
RH
2445 tcg_gen_movcond_i64(cmp->cond, dst, cmp->c1, cmp->c2,
2446 gen_load_fpr_D(dc, rs),
2447 gen_load_fpr_D(dc, rd));
2448 gen_store_fpr_D(dc, rd, dst);
f7ec8155
RH
2449#else
2450 qemu_build_not_reached();
2451#endif
7e480893
RH
2452}
2453
2454static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
2455{
f7ec8155 2456#ifdef TARGET_SPARC64
7e480893
RH
2457 int qd = QFPREG(rd);
2458 int qs = QFPREG(rs);
2459
2460 tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2], cmp->c1, cmp->c2,
2461 cpu_fpr[qs / 2], cpu_fpr[qd / 2]);
2462 tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, cmp->c2,
2463 cpu_fpr[qs / 2 + 1], cpu_fpr[qd / 2 + 1]);
2464
f9c816c0 2465 gen_update_fprs_dirty(dc, qd);
f7ec8155
RH
2466#else
2467 qemu_build_not_reached();
2468#endif
7e480893
RH
2469}
2470
f7ec8155 2471#ifdef TARGET_SPARC64
5d617bfb 2472static void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr)
8194f35a 2473{
b551ec04 2474 TCGv_i32 r_tl = tcg_temp_new_i32();
8194f35a
IK
2475
2476 /* load env->tl into r_tl */
ad75a51e 2477 tcg_gen_ld_i32(r_tl, tcg_env, offsetof(CPUSPARCState, tl));
8194f35a
IK
2478
2479 /* tl = [0 ... MAXTL_MASK] where MAXTL_MASK must be power of 2 */
b551ec04 2480 tcg_gen_andi_i32(r_tl, r_tl, MAXTL_MASK);
8194f35a
IK
2481
2482 /* calculate offset to current trap state from env->ts, reuse r_tl */
b551ec04 2483 tcg_gen_muli_i32(r_tl, r_tl, sizeof (trap_state));
ad75a51e 2484 tcg_gen_addi_ptr(r_tsptr, tcg_env, offsetof(CPUSPARCState, ts));
8194f35a
IK
2485
2486 /* tsptr = env->ts[env->tl & MAXTL_MASK] */
b551ec04
JF
2487 {
2488 TCGv_ptr r_tl_tmp = tcg_temp_new_ptr();
2489 tcg_gen_ext_i32_ptr(r_tl_tmp, r_tl);
2490 tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl_tmp);
b551ec04 2491 }
8194f35a
IK
2492}
2493#endif
2494
06c060d9
RH
2495static int extract_dfpreg(DisasContext *dc, int x)
2496{
2497 return DFPREG(x);
2498}
2499
2500static int extract_qfpreg(DisasContext *dc, int x)
2501{
2502 return QFPREG(x);
2503}
2504
878cc677
RH
2505/* Include the auto-generated decoder. */
2506#include "decode-insns.c.inc"
2507
2508#define TRANS(NAME, AVAIL, FUNC, ...) \
2509 static bool trans_##NAME(DisasContext *dc, arg_##NAME *a) \
2510 { return avail_##AVAIL(dc) && FUNC(dc, __VA_ARGS__); }
2511
2512#define avail_ALL(C) true
2513#ifdef TARGET_SPARC64
2514# define avail_32(C) false
af25071c 2515# define avail_ASR17(C) false
d0a11d25 2516# define avail_CASA(C) true
c2636853 2517# define avail_DIV(C) true
b5372650 2518# define avail_MUL(C) true
0faef01b 2519# define avail_POWERDOWN(C) false
878cc677 2520# define avail_64(C) true
5d617bfb 2521# define avail_GL(C) ((C)->def->features & CPU_FEATURE_GL)
af25071c 2522# define avail_HYPV(C) ((C)->def->features & CPU_FEATURE_HYPV)
b88ce6f2
RH
2523# define avail_VIS1(C) ((C)->def->features & CPU_FEATURE_VIS1)
2524# define avail_VIS2(C) ((C)->def->features & CPU_FEATURE_VIS2)
878cc677
RH
2525#else
2526# define avail_32(C) true
af25071c 2527# define avail_ASR17(C) ((C)->def->features & CPU_FEATURE_ASR17)
d0a11d25 2528# define avail_CASA(C) ((C)->def->features & CPU_FEATURE_CASA)
c2636853 2529# define avail_DIV(C) ((C)->def->features & CPU_FEATURE_DIV)
b5372650 2530# define avail_MUL(C) ((C)->def->features & CPU_FEATURE_MUL)
0faef01b 2531# define avail_POWERDOWN(C) ((C)->def->features & CPU_FEATURE_POWERDOWN)
878cc677 2532# define avail_64(C) false
5d617bfb 2533# define avail_GL(C) false
af25071c 2534# define avail_HYPV(C) false
b88ce6f2
RH
2535# define avail_VIS1(C) false
2536# define avail_VIS2(C) false
878cc677
RH
2537#endif
2538
2539/* Default case for non jump instructions. */
2540static bool advance_pc(DisasContext *dc)
2541{
2542 if (dc->npc & 3) {
2543 switch (dc->npc) {
2544 case DYNAMIC_PC:
2545 case DYNAMIC_PC_LOOKUP:
2546 dc->pc = dc->npc;
2547 gen_op_next_insn();
2548 break;
2549 case JUMP_PC:
2550 /* we can do a static jump */
2551 gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond);
2552 dc->base.is_jmp = DISAS_NORETURN;
2553 break;
2554 default:
2555 g_assert_not_reached();
2556 }
2557 } else {
2558 dc->pc = dc->npc;
2559 dc->npc = dc->npc + 4;
2560 }
2561 return true;
2562}
2563
6d2a0768
RH
2564/*
2565 * Major opcodes 00 and 01 -- branches, call, and sethi
2566 */
2567
276567aa
RH
2568static bool advance_jump_uncond_never(DisasContext *dc, bool annul)
2569{
2570 if (annul) {
2571 dc->pc = dc->npc + 4;
2572 dc->npc = dc->pc + 4;
2573 } else {
2574 dc->pc = dc->npc;
2575 dc->npc = dc->pc + 4;
2576 }
2577 return true;
2578}
2579
2580static bool advance_jump_uncond_always(DisasContext *dc, bool annul,
2581 target_ulong dest)
2582{
2583 if (annul) {
2584 dc->pc = dest;
2585 dc->npc = dest + 4;
2586 } else {
2587 dc->pc = dc->npc;
2588 dc->npc = dest;
2589 tcg_gen_mov_tl(cpu_pc, cpu_npc);
2590 }
2591 return true;
2592}
2593
9d4e2bc7
RH
2594static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
2595 bool annul, target_ulong dest)
276567aa 2596{
6b3e4cc6
RH
2597 target_ulong npc = dc->npc;
2598
276567aa 2599 if (annul) {
6b3e4cc6
RH
2600 TCGLabel *l1 = gen_new_label();
2601
9d4e2bc7 2602 tcg_gen_brcond_tl(tcg_invert_cond(cmp->cond), cmp->c1, cmp->c2, l1);
6b3e4cc6
RH
2603 gen_goto_tb(dc, 0, npc, dest);
2604 gen_set_label(l1);
2605 gen_goto_tb(dc, 1, npc + 4, npc + 8);
2606
2607 dc->base.is_jmp = DISAS_NORETURN;
276567aa 2608 } else {
6b3e4cc6
RH
2609 if (npc & 3) {
2610 switch (npc) {
2611 case DYNAMIC_PC:
2612 case DYNAMIC_PC_LOOKUP:
2613 tcg_gen_mov_tl(cpu_pc, cpu_npc);
2614 tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
9d4e2bc7
RH
2615 tcg_gen_movcond_tl(cmp->cond, cpu_npc,
2616 cmp->c1, cmp->c2,
6b3e4cc6
RH
2617 tcg_constant_tl(dest), cpu_npc);
2618 dc->pc = npc;
2619 break;
2620 default:
2621 g_assert_not_reached();
2622 }
2623 } else {
2624 dc->pc = npc;
2625 dc->jump_pc[0] = dest;
2626 dc->jump_pc[1] = npc + 4;
2627 dc->npc = JUMP_PC;
9d4e2bc7
RH
2628 if (cmp->is_bool) {
2629 tcg_gen_mov_tl(cpu_cond, cmp->c1);
2630 } else {
2631 tcg_gen_setcond_tl(cmp->cond, cpu_cond, cmp->c1, cmp->c2);
2632 }
6b3e4cc6 2633 }
276567aa
RH
2634 }
2635 return true;
2636}
2637
af25071c
RH
2638static bool raise_priv(DisasContext *dc)
2639{
2640 gen_exception(dc, TT_PRIV_INSN);
2641 return true;
2642}
2643
06c060d9
RH
2644static bool raise_unimpfpop(DisasContext *dc)
2645{
2646 gen_op_fpexception_im(dc, FSR_FTT_UNIMPFPOP);
2647 return true;
2648}
2649
2650static bool gen_trap_float128(DisasContext *dc)
2651{
2652 if (dc->def->features & CPU_FEATURE_FLOAT128) {
2653 return false;
2654 }
2655 return raise_unimpfpop(dc);
2656}
2657
276567aa
RH
2658static bool do_bpcc(DisasContext *dc, arg_bcc *a)
2659{
2660 target_long target = address_mask_i(dc, dc->pc + a->i * 4);
1ea9c62a 2661 DisasCompare cmp;
276567aa
RH
2662
2663 switch (a->cond) {
2664 case 0x0:
2665 return advance_jump_uncond_never(dc, a->a);
2666 case 0x8:
2667 return advance_jump_uncond_always(dc, a->a, target);
2668 default:
2669 flush_cond(dc);
1ea9c62a
RH
2670
2671 gen_compare(&cmp, a->cc, a->cond, dc);
9d4e2bc7 2672 return advance_jump_cond(dc, &cmp, a->a, target);
276567aa
RH
2673 }
2674}
2675
2676TRANS(Bicc, ALL, do_bpcc, a)
2677TRANS(BPcc, 64, do_bpcc, a)
2678
45196ea4
RH
2679static bool do_fbpfcc(DisasContext *dc, arg_bcc *a)
2680{
2681 target_long target = address_mask_i(dc, dc->pc + a->i * 4);
d5471936 2682 DisasCompare cmp;
45196ea4
RH
2683
2684 if (gen_trap_ifnofpu(dc)) {
2685 return true;
2686 }
2687 switch (a->cond) {
2688 case 0x0:
2689 return advance_jump_uncond_never(dc, a->a);
2690 case 0x8:
2691 return advance_jump_uncond_always(dc, a->a, target);
2692 default:
2693 flush_cond(dc);
d5471936
RH
2694
2695 gen_fcompare(&cmp, a->cc, a->cond);
9d4e2bc7 2696 return advance_jump_cond(dc, &cmp, a->a, target);
45196ea4
RH
2697 }
2698}
2699
2700TRANS(FBPfcc, 64, do_fbpfcc, a)
2701TRANS(FBfcc, ALL, do_fbpfcc, a)
2702
ab9ffe98
RH
2703static bool trans_BPr(DisasContext *dc, arg_BPr *a)
2704{
2705 target_long target = address_mask_i(dc, dc->pc + a->i * 4);
2706 DisasCompare cmp;
2707
2708 if (!avail_64(dc)) {
2709 return false;
2710 }
2711 if (gen_tcg_cond_reg[a->cond] == TCG_COND_NEVER) {
2712 return false;
2713 }
2714
2715 flush_cond(dc);
2716 gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
9d4e2bc7 2717 return advance_jump_cond(dc, &cmp, a->a, target);
ab9ffe98
RH
2718}
2719
23ada1b1
RH
2720static bool trans_CALL(DisasContext *dc, arg_CALL *a)
2721{
2722 target_long target = address_mask_i(dc, dc->pc + a->i * 4);
2723
2724 gen_store_gpr(dc, 15, tcg_constant_tl(dc->pc));
2725 gen_mov_pc_npc(dc);
2726 dc->npc = target;
2727 return true;
2728}
2729
45196ea4
RH
2730static bool trans_NCP(DisasContext *dc, arg_NCP *a)
2731{
2732 /*
2733 * For sparc32, always generate the no-coprocessor exception.
2734 * For sparc64, always generate illegal instruction.
2735 */
2736#ifdef TARGET_SPARC64
2737 return false;
2738#else
2739 gen_exception(dc, TT_NCP_INSN);
2740 return true;
2741#endif
2742}
2743
6d2a0768
RH
2744static bool trans_SETHI(DisasContext *dc, arg_SETHI *a)
2745{
2746 /* Special-case %g0 because that's the canonical nop. */
2747 if (a->rd) {
2748 gen_store_gpr(dc, a->rd, tcg_constant_tl((uint32_t)a->i << 10));
2749 }
2750 return advance_pc(dc);
2751}
2752
0faef01b
RH
2753/*
2754 * Major Opcode 10 -- integer, floating-point, vis, and system insns.
2755 */
2756
30376636
RH
2757static bool do_tcc(DisasContext *dc, int cond, int cc,
2758 int rs1, bool imm, int rs2_or_imm)
2759{
2760 int mask = ((dc->def->features & CPU_FEATURE_HYPV) && supervisor(dc)
2761 ? UA2005_HTRAP_MASK : V8_TRAP_MASK);
2762 DisasCompare cmp;
2763 TCGLabel *lab;
2764 TCGv_i32 trap;
2765
2766 /* Trap never. */
2767 if (cond == 0) {
2768 return advance_pc(dc);
2769 }
2770
2771 /*
2772 * Immediate traps are the most common case. Since this value is
2773 * live across the branch, it really pays to evaluate the constant.
2774 */
2775 if (rs1 == 0 && (imm || rs2_or_imm == 0)) {
2776 trap = tcg_constant_i32((rs2_or_imm & mask) + TT_TRAP);
2777 } else {
2778 trap = tcg_temp_new_i32();
2779 tcg_gen_trunc_tl_i32(trap, gen_load_gpr(dc, rs1));
2780 if (imm) {
2781 tcg_gen_addi_i32(trap, trap, rs2_or_imm);
2782 } else {
2783 TCGv_i32 t2 = tcg_temp_new_i32();
2784 tcg_gen_trunc_tl_i32(t2, gen_load_gpr(dc, rs2_or_imm));
2785 tcg_gen_add_i32(trap, trap, t2);
2786 }
2787 tcg_gen_andi_i32(trap, trap, mask);
2788 tcg_gen_addi_i32(trap, trap, TT_TRAP);
2789 }
2790
2791 /* Trap always. */
2792 if (cond == 8) {
2793 save_state(dc);
2794 gen_helper_raise_exception(tcg_env, trap);
2795 dc->base.is_jmp = DISAS_NORETURN;
2796 return true;
2797 }
2798
2799 /* Conditional trap. */
2800 flush_cond(dc);
2801 lab = delay_exceptionv(dc, trap);
2802 gen_compare(&cmp, cc, cond, dc);
2803 tcg_gen_brcond_tl(cmp.cond, cmp.c1, cmp.c2, lab);
2804
2805 return advance_pc(dc);
2806}
2807
2808static bool trans_Tcc_r(DisasContext *dc, arg_Tcc_r *a)
2809{
2810 if (avail_32(dc) && a->cc) {
2811 return false;
2812 }
2813 return do_tcc(dc, a->cond, a->cc, a->rs1, false, a->rs2);
2814}
2815
2816static bool trans_Tcc_i_v7(DisasContext *dc, arg_Tcc_i_v7 *a)
2817{
2818 if (avail_64(dc)) {
2819 return false;
2820 }
2821 return do_tcc(dc, a->cond, 0, a->rs1, true, a->i);
2822}
2823
2824static bool trans_Tcc_i_v9(DisasContext *dc, arg_Tcc_i_v9 *a)
2825{
2826 if (avail_32(dc)) {
2827 return false;
2828 }
2829 return do_tcc(dc, a->cond, a->cc, a->rs1, true, a->i);
2830}
2831
af25071c
RH
2832static bool trans_STBAR(DisasContext *dc, arg_STBAR *a)
2833{
2834 tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC);
2835 return advance_pc(dc);
2836}
2837
2838static bool trans_MEMBAR(DisasContext *dc, arg_MEMBAR *a)
2839{
2840 if (avail_32(dc)) {
2841 return false;
2842 }
2843 if (a->mmask) {
2844 /* Note TCG_MO_* was modeled on sparc64, so mmask matches. */
2845 tcg_gen_mb(a->mmask | TCG_BAR_SC);
2846 }
2847 if (a->cmask) {
2848 /* For #Sync, etc, end the TB to recognize interrupts. */
2849 dc->base.is_jmp = DISAS_EXIT;
2850 }
2851 return advance_pc(dc);
2852}
2853
2854static bool do_rd_special(DisasContext *dc, bool priv, int rd,
2855 TCGv (*func)(DisasContext *, TCGv))
2856{
2857 if (!priv) {
2858 return raise_priv(dc);
2859 }
2860 gen_store_gpr(dc, rd, func(dc, gen_dest_gpr(dc, rd)));
2861 return advance_pc(dc);
2862}
2863
2864static TCGv do_rdy(DisasContext *dc, TCGv dst)
2865{
2866 return cpu_y;
2867}
2868
2869static bool trans_RDY(DisasContext *dc, arg_RDY *a)
2870{
2871 /*
2872 * TODO: Need a feature bit for sparcv8. In the meantime, treat all
2873 * 32-bit cpus like sparcv7, which ignores the rs1 field.
2874 * This matches after all other ASR, so Leon3 Asr17 is handled first.
2875 */
2876 if (avail_64(dc) && a->rs1 != 0) {
2877 return false;
2878 }
2879 return do_rd_special(dc, true, a->rd, do_rdy);
2880}
2881
2882static TCGv do_rd_leon3_config(DisasContext *dc, TCGv dst)
2883{
2884 uint32_t val;
2885
2886 /*
2887 * TODO: There are many more fields to be filled,
2888 * some of which are writable.
2889 */
2890 val = dc->def->nwindows - 1; /* [4:0] NWIN */
2891 val |= 1 << 8; /* [8] V8 */
2892
2893 return tcg_constant_tl(val);
2894}
2895
2896TRANS(RDASR17, ASR17, do_rd_special, true, a->rd, do_rd_leon3_config)
2897
2898static TCGv do_rdccr(DisasContext *dc, TCGv dst)
2899{
2900 update_psr(dc);
2901 gen_helper_rdccr(dst, tcg_env);
2902 return dst;
2903}
2904
2905TRANS(RDCCR, 64, do_rd_special, true, a->rd, do_rdccr)
2906
2907static TCGv do_rdasi(DisasContext *dc, TCGv dst)
2908{
2909#ifdef TARGET_SPARC64
2910 return tcg_constant_tl(dc->asi);
2911#else
2912 qemu_build_not_reached();
2913#endif
2914}
2915
2916TRANS(RDASI, 64, do_rd_special, true, a->rd, do_rdasi)
2917
2918static TCGv do_rdtick(DisasContext *dc, TCGv dst)
2919{
2920 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
2921
2922 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick));
2923 if (translator_io_start(&dc->base)) {
2924 dc->base.is_jmp = DISAS_EXIT;
2925 }
2926 gen_helper_tick_get_count(dst, tcg_env, r_tickptr,
2927 tcg_constant_i32(dc->mem_idx));
2928 return dst;
2929}
2930
2931/* TODO: non-priv access only allowed when enabled. */
2932TRANS(RDTICK, 64, do_rd_special, true, a->rd, do_rdtick)
2933
2934static TCGv do_rdpc(DisasContext *dc, TCGv dst)
2935{
2936 return tcg_constant_tl(address_mask_i(dc, dc->pc));
2937}
2938
2939TRANS(RDPC, 64, do_rd_special, true, a->rd, do_rdpc)
2940
2941static TCGv do_rdfprs(DisasContext *dc, TCGv dst)
2942{
2943 tcg_gen_ext_i32_tl(dst, cpu_fprs);
2944 return dst;
2945}
2946
2947TRANS(RDFPRS, 64, do_rd_special, true, a->rd, do_rdfprs)
2948
2949static TCGv do_rdgsr(DisasContext *dc, TCGv dst)
2950{
2951 gen_trap_ifnofpu(dc);
2952 return cpu_gsr;
2953}
2954
2955TRANS(RDGSR, 64, do_rd_special, true, a->rd, do_rdgsr)
2956
2957static TCGv do_rdsoftint(DisasContext *dc, TCGv dst)
2958{
2959 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(softint));
2960 return dst;
2961}
2962
2963TRANS(RDSOFTINT, 64, do_rd_special, supervisor(dc), a->rd, do_rdsoftint)
2964
2965static TCGv do_rdtick_cmpr(DisasContext *dc, TCGv dst)
2966{
577efa45
RH
2967 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(tick_cmpr));
2968 return dst;
af25071c
RH
2969}
2970
2971/* TODO: non-priv access only allowed when enabled. */
2972TRANS(RDTICK_CMPR, 64, do_rd_special, true, a->rd, do_rdtick_cmpr)
2973
2974static TCGv do_rdstick(DisasContext *dc, TCGv dst)
2975{
2976 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
2977
2978 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(stick));
2979 if (translator_io_start(&dc->base)) {
2980 dc->base.is_jmp = DISAS_EXIT;
2981 }
2982 gen_helper_tick_get_count(dst, tcg_env, r_tickptr,
2983 tcg_constant_i32(dc->mem_idx));
2984 return dst;
2985}
2986
2987/* TODO: non-priv access only allowed when enabled. */
2988TRANS(RDSTICK, 64, do_rd_special, true, a->rd, do_rdstick)
2989
2990static TCGv do_rdstick_cmpr(DisasContext *dc, TCGv dst)
2991{
577efa45
RH
2992 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(stick_cmpr));
2993 return dst;
af25071c
RH
2994}
2995
2996/* TODO: supervisor access only allowed when enabled by hypervisor. */
2997TRANS(RDSTICK_CMPR, 64, do_rd_special, supervisor(dc), a->rd, do_rdstick_cmpr)
2998
2999/*
3000 * UltraSPARC-T1 Strand status.
3001 * HYPV check maybe not enough, UA2005 & UA2007 describe
3002 * this ASR as impl. dep
3003 */
3004static TCGv do_rdstrand_status(DisasContext *dc, TCGv dst)
3005{
3006 return tcg_constant_tl(1);
3007}
3008
3009TRANS(RDSTRAND_STATUS, HYPV, do_rd_special, true, a->rd, do_rdstrand_status)
3010
668bb9b7
RH
3011static TCGv do_rdpsr(DisasContext *dc, TCGv dst)
3012{
3013 update_psr(dc);
3014 gen_helper_rdpsr(dst, tcg_env);
3015 return dst;
3016}
3017
3018TRANS(RDPSR, 32, do_rd_special, supervisor(dc), a->rd, do_rdpsr)
3019
3020static TCGv do_rdhpstate(DisasContext *dc, TCGv dst)
3021{
3022 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hpstate));
3023 return dst;
3024}
3025
3026TRANS(RDHPR_hpstate, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhpstate)
3027
3028static TCGv do_rdhtstate(DisasContext *dc, TCGv dst)
3029{
3030 TCGv_i32 tl = tcg_temp_new_i32();
3031 TCGv_ptr tp = tcg_temp_new_ptr();
3032
3033 tcg_gen_ld_i32(tl, tcg_env, env64_field_offsetof(tl));
3034 tcg_gen_andi_i32(tl, tl, MAXTL_MASK);
3035 tcg_gen_shli_i32(tl, tl, 3);
3036 tcg_gen_ext_i32_ptr(tp, tl);
3037 tcg_gen_add_ptr(tp, tp, tcg_env);
3038
3039 tcg_gen_ld_tl(dst, tp, env64_field_offsetof(htstate));
3040 return dst;
3041}
3042
3043TRANS(RDHPR_htstate, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhtstate)
3044
3045static TCGv do_rdhintp(DisasContext *dc, TCGv dst)
3046{
2da789de
RH
3047 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hintp));
3048 return dst;
668bb9b7
RH
3049}
3050
3051TRANS(RDHPR_hintp, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhintp)
3052
3053static TCGv do_rdhtba(DisasContext *dc, TCGv dst)
3054{
2da789de
RH
3055 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(htba));
3056 return dst;
668bb9b7
RH
3057}
3058
3059TRANS(RDHPR_htba, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhtba)
3060
3061static TCGv do_rdhver(DisasContext *dc, TCGv dst)
3062{
2da789de
RH
3063 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hver));
3064 return dst;
668bb9b7
RH
3065}
3066
3067TRANS(RDHPR_hver, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhver)
3068
3069static TCGv do_rdhstick_cmpr(DisasContext *dc, TCGv dst)
3070{
577efa45
RH
3071 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hstick_cmpr));
3072 return dst;
668bb9b7
RH
3073}
3074
3075TRANS(RDHPR_hstick_cmpr, HYPV, do_rd_special, hypervisor(dc), a->rd,
3076 do_rdhstick_cmpr)
3077
5d617bfb
RH
3078static TCGv do_rdwim(DisasContext *dc, TCGv dst)
3079{
cd6269f7
RH
3080 tcg_gen_ld_tl(dst, tcg_env, env32_field_offsetof(wim));
3081 return dst;
5d617bfb
RH
3082}
3083
3084TRANS(RDWIM, 32, do_rd_special, supervisor(dc), a->rd, do_rdwim)
3085
3086static TCGv do_rdtpc(DisasContext *dc, TCGv dst)
3087{
3088#ifdef TARGET_SPARC64
3089 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3090
3091 gen_load_trap_state_at_tl(r_tsptr);
3092 tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tpc));
3093 return dst;
3094#else
3095 qemu_build_not_reached();
3096#endif
3097}
3098
3099TRANS(RDPR_tpc, 64, do_rd_special, supervisor(dc), a->rd, do_rdtpc)
3100
3101static TCGv do_rdtnpc(DisasContext *dc, TCGv dst)
3102{
3103#ifdef TARGET_SPARC64
3104 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3105
3106 gen_load_trap_state_at_tl(r_tsptr);
3107 tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tnpc));
3108 return dst;
3109#else
3110 qemu_build_not_reached();
3111#endif
3112}
3113
3114TRANS(RDPR_tnpc, 64, do_rd_special, supervisor(dc), a->rd, do_rdtnpc)
3115
3116static TCGv do_rdtstate(DisasContext *dc, TCGv dst)
3117{
3118#ifdef TARGET_SPARC64
3119 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3120
3121 gen_load_trap_state_at_tl(r_tsptr);
3122 tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tstate));
3123 return dst;
3124#else
3125 qemu_build_not_reached();
3126#endif
3127}
3128
3129TRANS(RDPR_tstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdtstate)
3130
3131static TCGv do_rdtt(DisasContext *dc, TCGv dst)
3132{
3133#ifdef TARGET_SPARC64
3134 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3135
3136 gen_load_trap_state_at_tl(r_tsptr);
3137 tcg_gen_ld32s_tl(dst, r_tsptr, offsetof(trap_state, tt));
3138 return dst;
3139#else
3140 qemu_build_not_reached();
3141#endif
3142}
3143
3144TRANS(RDPR_tt, 64, do_rd_special, supervisor(dc), a->rd, do_rdtt)
3145TRANS(RDPR_tick, 64, do_rd_special, supervisor(dc), a->rd, do_rdtick)
3146
3147static TCGv do_rdtba(DisasContext *dc, TCGv dst)
3148{
3149 return cpu_tbr;
3150}
3151
e8325dc0 3152TRANS(RDTBR, 32, do_rd_special, supervisor(dc), a->rd, do_rdtba)
5d617bfb
RH
3153TRANS(RDPR_tba, 64, do_rd_special, supervisor(dc), a->rd, do_rdtba)
3154
3155static TCGv do_rdpstate(DisasContext *dc, TCGv dst)
3156{
3157 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(pstate));
3158 return dst;
3159}
3160
3161TRANS(RDPR_pstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdpstate)
3162
3163static TCGv do_rdtl(DisasContext *dc, TCGv dst)
3164{
3165 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(tl));
3166 return dst;
3167}
3168
3169TRANS(RDPR_tl, 64, do_rd_special, supervisor(dc), a->rd, do_rdtl)
3170
3171static TCGv do_rdpil(DisasContext *dc, TCGv dst)
3172{
3173 tcg_gen_ld32s_tl(dst, tcg_env, env_field_offsetof(psrpil));
3174 return dst;
3175}
3176
3177TRANS(RDPR_pil, 64, do_rd_special, supervisor(dc), a->rd, do_rdpil)
3178
3179static TCGv do_rdcwp(DisasContext *dc, TCGv dst)
3180{
3181 gen_helper_rdcwp(dst, tcg_env);
3182 return dst;
3183}
3184
3185TRANS(RDPR_cwp, 64, do_rd_special, supervisor(dc), a->rd, do_rdcwp)
3186
3187static TCGv do_rdcansave(DisasContext *dc, TCGv dst)
3188{
3189 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(cansave));
3190 return dst;
3191}
3192
3193TRANS(RDPR_cansave, 64, do_rd_special, supervisor(dc), a->rd, do_rdcansave)
3194
3195static TCGv do_rdcanrestore(DisasContext *dc, TCGv dst)
3196{
3197 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(canrestore));
3198 return dst;
3199}
3200
3201TRANS(RDPR_canrestore, 64, do_rd_special, supervisor(dc), a->rd,
3202 do_rdcanrestore)
3203
3204static TCGv do_rdcleanwin(DisasContext *dc, TCGv dst)
3205{
3206 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(cleanwin));
3207 return dst;
3208}
3209
3210TRANS(RDPR_cleanwin, 64, do_rd_special, supervisor(dc), a->rd, do_rdcleanwin)
3211
3212static TCGv do_rdotherwin(DisasContext *dc, TCGv dst)
3213{
3214 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(otherwin));
3215 return dst;
3216}
3217
3218TRANS(RDPR_otherwin, 64, do_rd_special, supervisor(dc), a->rd, do_rdotherwin)
3219
3220static TCGv do_rdwstate(DisasContext *dc, TCGv dst)
3221{
3222 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(wstate));
3223 return dst;
3224}
3225
3226TRANS(RDPR_wstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdwstate)
3227
3228static TCGv do_rdgl(DisasContext *dc, TCGv dst)
3229{
3230 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(gl));
3231 return dst;
3232}
3233
3234TRANS(RDPR_gl, GL, do_rd_special, supervisor(dc), a->rd, do_rdgl)
3235
3236/* UA2005 strand status */
3237static TCGv do_rdssr(DisasContext *dc, TCGv dst)
3238{
2da789de
RH
3239 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(ssr));
3240 return dst;
5d617bfb
RH
3241}
3242
3243TRANS(RDPR_strand_status, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdssr)
3244
3245static TCGv do_rdver(DisasContext *dc, TCGv dst)
3246{
2da789de
RH
3247 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(version));
3248 return dst;
5d617bfb
RH
3249}
3250
3251TRANS(RDPR_ver, 64, do_rd_special, supervisor(dc), a->rd, do_rdver)
3252
e8325dc0
RH
3253static bool trans_FLUSHW(DisasContext *dc, arg_FLUSHW *a)
3254{
3255 if (avail_64(dc)) {
3256 gen_helper_flushw(tcg_env);
3257 return advance_pc(dc);
3258 }
3259 return false;
3260}
3261
0faef01b
RH
3262static bool do_wr_special(DisasContext *dc, arg_r_r_ri *a, bool priv,
3263 void (*func)(DisasContext *, TCGv))
3264{
3265 TCGv src;
3266
3267 /* For simplicity, we under-decoded the rs2 form. */
3268 if (!a->imm && (a->rs2_or_imm & ~0x1f)) {
3269 return false;
3270 }
3271 if (!priv) {
3272 return raise_priv(dc);
3273 }
3274
3275 if (a->rs1 == 0 && (a->imm || a->rs2_or_imm == 0)) {
3276 src = tcg_constant_tl(a->rs2_or_imm);
3277 } else {
3278 TCGv src1 = gen_load_gpr(dc, a->rs1);
3279 if (a->rs2_or_imm == 0) {
3280 src = src1;
3281 } else {
3282 src = tcg_temp_new();
3283 if (a->imm) {
3284 tcg_gen_xori_tl(src, src1, a->rs2_or_imm);
3285 } else {
3286 tcg_gen_xor_tl(src, src1, gen_load_gpr(dc, a->rs2_or_imm));
3287 }
3288 }
3289 }
3290 func(dc, src);
3291 return advance_pc(dc);
3292}
3293
3294static void do_wry(DisasContext *dc, TCGv src)
3295{
3296 tcg_gen_ext32u_tl(cpu_y, src);
3297}
3298
3299TRANS(WRY, ALL, do_wr_special, a, true, do_wry)
3300
3301static void do_wrccr(DisasContext *dc, TCGv src)
3302{
3303 gen_helper_wrccr(tcg_env, src);
3304}
3305
3306TRANS(WRCCR, 64, do_wr_special, a, true, do_wrccr)
3307
3308static void do_wrasi(DisasContext *dc, TCGv src)
3309{
3310 TCGv tmp = tcg_temp_new();
3311
3312 tcg_gen_ext8u_tl(tmp, src);
3313 tcg_gen_st32_tl(tmp, tcg_env, env64_field_offsetof(asi));
3314 /* End TB to notice changed ASI. */
3315 dc->base.is_jmp = DISAS_EXIT;
3316}
3317
3318TRANS(WRASI, 64, do_wr_special, a, true, do_wrasi)
3319
3320static void do_wrfprs(DisasContext *dc, TCGv src)
3321{
3322#ifdef TARGET_SPARC64
3323 tcg_gen_trunc_tl_i32(cpu_fprs, src);
3324 dc->fprs_dirty = 0;
3325 dc->base.is_jmp = DISAS_EXIT;
3326#else
3327 qemu_build_not_reached();
3328#endif
3329}
3330
3331TRANS(WRFPRS, 64, do_wr_special, a, true, do_wrfprs)
3332
3333static void do_wrgsr(DisasContext *dc, TCGv src)
3334{
3335 gen_trap_ifnofpu(dc);
3336 tcg_gen_mov_tl(cpu_gsr, src);
3337}
3338
3339TRANS(WRGSR, 64, do_wr_special, a, true, do_wrgsr)
3340
3341static void do_wrsoftint_set(DisasContext *dc, TCGv src)
3342{
3343 gen_helper_set_softint(tcg_env, src);
3344}
3345
3346TRANS(WRSOFTINT_SET, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_set)
3347
3348static void do_wrsoftint_clr(DisasContext *dc, TCGv src)
3349{
3350 gen_helper_clear_softint(tcg_env, src);
3351}
3352
3353TRANS(WRSOFTINT_CLR, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_clr)
3354
3355static void do_wrsoftint(DisasContext *dc, TCGv src)
3356{
3357 gen_helper_write_softint(tcg_env, src);
3358}
3359
3360TRANS(WRSOFTINT, 64, do_wr_special, a, supervisor(dc), do_wrsoftint)
3361
3362static void do_wrtick_cmpr(DisasContext *dc, TCGv src)
3363{
0faef01b
RH
3364 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3365
577efa45
RH
3366 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(tick_cmpr));
3367 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick));
0faef01b 3368 translator_io_start(&dc->base);
577efa45 3369 gen_helper_tick_set_limit(r_tickptr, src);
0faef01b
RH
3370 /* End TB to handle timer interrupt */
3371 dc->base.is_jmp = DISAS_EXIT;
0faef01b
RH
3372}
3373
3374TRANS(WRTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrtick_cmpr)
3375
3376static void do_wrstick(DisasContext *dc, TCGv src)
3377{
3378#ifdef TARGET_SPARC64
3379 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3380
3381 tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick));
3382 translator_io_start(&dc->base);
3383 gen_helper_tick_set_count(r_tickptr, src);
3384 /* End TB to handle timer interrupt */
3385 dc->base.is_jmp = DISAS_EXIT;
3386#else
3387 qemu_build_not_reached();
3388#endif
3389}
3390
3391TRANS(WRSTICK, 64, do_wr_special, a, supervisor(dc), do_wrstick)
3392
3393static void do_wrstick_cmpr(DisasContext *dc, TCGv src)
3394{
0faef01b
RH
3395 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3396
577efa45
RH
3397 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(stick_cmpr));
3398 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(stick));
0faef01b 3399 translator_io_start(&dc->base);
577efa45 3400 gen_helper_tick_set_limit(r_tickptr, src);
0faef01b
RH
3401 /* End TB to handle timer interrupt */
3402 dc->base.is_jmp = DISAS_EXIT;
0faef01b
RH
3403}
3404
3405TRANS(WRSTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrstick_cmpr)
3406
3407static void do_wrpowerdown(DisasContext *dc, TCGv src)
3408{
3409 save_state(dc);
3410 gen_helper_power_down(tcg_env);
3411}
3412
3413TRANS(WRPOWERDOWN, POWERDOWN, do_wr_special, a, supervisor(dc), do_wrpowerdown)
3414
25524734
RH
3415static void do_wrpsr(DisasContext *dc, TCGv src)
3416{
3417 gen_helper_wrpsr(tcg_env, src);
3418 tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
3419 dc->cc_op = CC_OP_FLAGS;
3420 dc->base.is_jmp = DISAS_EXIT;
3421}
3422
3423TRANS(WRPSR, 32, do_wr_special, a, supervisor(dc), do_wrpsr)
3424
9422278e
RH
3425static void do_wrwim(DisasContext *dc, TCGv src)
3426{
3427 target_ulong mask = MAKE_64BIT_MASK(0, dc->def->nwindows);
cd6269f7
RH
3428 TCGv tmp = tcg_temp_new();
3429
3430 tcg_gen_andi_tl(tmp, src, mask);
3431 tcg_gen_st_tl(tmp, tcg_env, env32_field_offsetof(wim));
9422278e
RH
3432}
3433
3434TRANS(WRWIM, 32, do_wr_special, a, supervisor(dc), do_wrwim)
3435
3436static void do_wrtpc(DisasContext *dc, TCGv src)
3437{
3438#ifdef TARGET_SPARC64
3439 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3440
3441 gen_load_trap_state_at_tl(r_tsptr);
3442 tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tpc));
3443#else
3444 qemu_build_not_reached();
3445#endif
3446}
3447
3448TRANS(WRPR_tpc, 64, do_wr_special, a, supervisor(dc), do_wrtpc)
3449
3450static void do_wrtnpc(DisasContext *dc, TCGv src)
3451{
3452#ifdef TARGET_SPARC64
3453 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3454
3455 gen_load_trap_state_at_tl(r_tsptr);
3456 tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tnpc));
3457#else
3458 qemu_build_not_reached();
3459#endif
3460}
3461
3462TRANS(WRPR_tnpc, 64, do_wr_special, a, supervisor(dc), do_wrtnpc)
3463
3464static void do_wrtstate(DisasContext *dc, TCGv src)
3465{
3466#ifdef TARGET_SPARC64
3467 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3468
3469 gen_load_trap_state_at_tl(r_tsptr);
3470 tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tstate));
3471#else
3472 qemu_build_not_reached();
3473#endif
3474}
3475
3476TRANS(WRPR_tstate, 64, do_wr_special, a, supervisor(dc), do_wrtstate)
3477
3478static void do_wrtt(DisasContext *dc, TCGv src)
3479{
3480#ifdef TARGET_SPARC64
3481 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3482
3483 gen_load_trap_state_at_tl(r_tsptr);
3484 tcg_gen_st32_tl(src, r_tsptr, offsetof(trap_state, tt));
3485#else
3486 qemu_build_not_reached();
3487#endif
3488}
3489
3490TRANS(WRPR_tt, 64, do_wr_special, a, supervisor(dc), do_wrtt)
3491
3492static void do_wrtick(DisasContext *dc, TCGv src)
3493{
3494 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3495
3496 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick));
3497 translator_io_start(&dc->base);
3498 gen_helper_tick_set_count(r_tickptr, src);
3499 /* End TB to handle timer interrupt */
3500 dc->base.is_jmp = DISAS_EXIT;
3501}
3502
3503TRANS(WRPR_tick, 64, do_wr_special, a, supervisor(dc), do_wrtick)
3504
3505static void do_wrtba(DisasContext *dc, TCGv src)
3506{
3507 tcg_gen_mov_tl(cpu_tbr, src);
3508}
3509
3510TRANS(WRPR_tba, 64, do_wr_special, a, supervisor(dc), do_wrtba)
3511
3512static void do_wrpstate(DisasContext *dc, TCGv src)
3513{
3514 save_state(dc);
3515 if (translator_io_start(&dc->base)) {
3516 dc->base.is_jmp = DISAS_EXIT;
3517 }
3518 gen_helper_wrpstate(tcg_env, src);
3519 dc->npc = DYNAMIC_PC;
3520}
3521
3522TRANS(WRPR_pstate, 64, do_wr_special, a, supervisor(dc), do_wrpstate)
3523
3524static void do_wrtl(DisasContext *dc, TCGv src)
3525{
3526 save_state(dc);
3527 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(tl));
3528 dc->npc = DYNAMIC_PC;
3529}
3530
3531TRANS(WRPR_tl, 64, do_wr_special, a, supervisor(dc), do_wrtl)
3532
3533static void do_wrpil(DisasContext *dc, TCGv src)
3534{
3535 if (translator_io_start(&dc->base)) {
3536 dc->base.is_jmp = DISAS_EXIT;
3537 }
3538 gen_helper_wrpil(tcg_env, src);
3539}
3540
3541TRANS(WRPR_pil, 64, do_wr_special, a, supervisor(dc), do_wrpil)
3542
3543static void do_wrcwp(DisasContext *dc, TCGv src)
3544{
3545 gen_helper_wrcwp(tcg_env, src);
3546}
3547
3548TRANS(WRPR_cwp, 64, do_wr_special, a, supervisor(dc), do_wrcwp)
3549
3550static void do_wrcansave(DisasContext *dc, TCGv src)
3551{
3552 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(cansave));
3553}
3554
3555TRANS(WRPR_cansave, 64, do_wr_special, a, supervisor(dc), do_wrcansave)
3556
3557static void do_wrcanrestore(DisasContext *dc, TCGv src)
3558{
3559 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(canrestore));
3560}
3561
3562TRANS(WRPR_canrestore, 64, do_wr_special, a, supervisor(dc), do_wrcanrestore)
3563
3564static void do_wrcleanwin(DisasContext *dc, TCGv src)
3565{
3566 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(cleanwin));
3567}
3568
3569TRANS(WRPR_cleanwin, 64, do_wr_special, a, supervisor(dc), do_wrcleanwin)
3570
3571static void do_wrotherwin(DisasContext *dc, TCGv src)
3572{
3573 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(otherwin));
3574}
3575
3576TRANS(WRPR_otherwin, 64, do_wr_special, a, supervisor(dc), do_wrotherwin)
3577
3578static void do_wrwstate(DisasContext *dc, TCGv src)
3579{
3580 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(wstate));
3581}
3582
3583TRANS(WRPR_wstate, 64, do_wr_special, a, supervisor(dc), do_wrwstate)
3584
3585static void do_wrgl(DisasContext *dc, TCGv src)
3586{
3587 gen_helper_wrgl(tcg_env, src);
3588}
3589
3590TRANS(WRPR_gl, GL, do_wr_special, a, supervisor(dc), do_wrgl)
3591
3592/* UA2005 strand status */
3593static void do_wrssr(DisasContext *dc, TCGv src)
3594{
2da789de 3595 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(ssr));
9422278e
RH
3596}
3597
3598TRANS(WRPR_strand_status, HYPV, do_wr_special, a, hypervisor(dc), do_wrssr)
3599
bb97f2f5
RH
3600TRANS(WRTBR, 32, do_wr_special, a, supervisor(dc), do_wrtba)
3601
3602static void do_wrhpstate(DisasContext *dc, TCGv src)
3603{
3604 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hpstate));
3605 dc->base.is_jmp = DISAS_EXIT;
3606}
3607
3608TRANS(WRHPR_hpstate, HYPV, do_wr_special, a, hypervisor(dc), do_wrhpstate)
3609
3610static void do_wrhtstate(DisasContext *dc, TCGv src)
3611{
3612 TCGv_i32 tl = tcg_temp_new_i32();
3613 TCGv_ptr tp = tcg_temp_new_ptr();
3614
3615 tcg_gen_ld_i32(tl, tcg_env, env64_field_offsetof(tl));
3616 tcg_gen_andi_i32(tl, tl, MAXTL_MASK);
3617 tcg_gen_shli_i32(tl, tl, 3);
3618 tcg_gen_ext_i32_ptr(tp, tl);
3619 tcg_gen_add_ptr(tp, tp, tcg_env);
3620
3621 tcg_gen_st_tl(src, tp, env64_field_offsetof(htstate));
3622}
3623
3624TRANS(WRHPR_htstate, HYPV, do_wr_special, a, hypervisor(dc), do_wrhtstate)
3625
3626static void do_wrhintp(DisasContext *dc, TCGv src)
3627{
2da789de 3628 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hintp));
bb97f2f5
RH
3629}
3630
3631TRANS(WRHPR_hintp, HYPV, do_wr_special, a, hypervisor(dc), do_wrhintp)
3632
3633static void do_wrhtba(DisasContext *dc, TCGv src)
3634{
2da789de 3635 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(htba));
bb97f2f5
RH
3636}
3637
3638TRANS(WRHPR_htba, HYPV, do_wr_special, a, hypervisor(dc), do_wrhtba)
3639
3640static void do_wrhstick_cmpr(DisasContext *dc, TCGv src)
3641{
3642 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3643
577efa45 3644 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hstick_cmpr));
bb97f2f5
RH
3645 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(hstick));
3646 translator_io_start(&dc->base);
577efa45 3647 gen_helper_tick_set_limit(r_tickptr, src);
bb97f2f5
RH
3648 /* End TB to handle timer interrupt */
3649 dc->base.is_jmp = DISAS_EXIT;
3650}
3651
3652TRANS(WRHPR_hstick_cmpr, HYPV, do_wr_special, a, hypervisor(dc),
3653 do_wrhstick_cmpr)
3654
25524734
RH
3655static bool do_saved_restored(DisasContext *dc, bool saved)
3656{
3657 if (!supervisor(dc)) {
3658 return raise_priv(dc);
3659 }
3660 if (saved) {
3661 gen_helper_saved(tcg_env);
3662 } else {
3663 gen_helper_restored(tcg_env);
3664 }
3665 return advance_pc(dc);
3666}
3667
3668TRANS(SAVED, 64, do_saved_restored, true)
3669TRANS(RESTORED, 64, do_saved_restored, false)
3670
d3825800
RH
3671static bool trans_NOP(DisasContext *dc, arg_NOP *a)
3672{
3673 return advance_pc(dc);
3674}
3675
5458fd31
RH
3676/*
3677 * TODO: Need a feature bit for sparcv8.
3678 * In the meantime, treat all 32-bit cpus like sparcv7.
3679 */
3680TRANS(NOP_v7, 32, trans_NOP, a)
3681TRANS(NOP_v9, 64, trans_NOP, a)
0faef01b 3682
428881de
RH
3683static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
3684 void (*func)(TCGv, TCGv, TCGv),
2a45b736
RH
3685 void (*funci)(TCGv, TCGv, target_long),
3686 bool logic_cc)
428881de
RH
3687{
3688 TCGv dst, src1;
3689
3690 /* For simplicity, we under-decoded the rs2 form. */
3691 if (!a->imm && a->rs2_or_imm & ~0x1f) {
3692 return false;
3693 }
3694
2a45b736
RH
3695 if (logic_cc) {
3696 dst = cpu_cc_N;
3697 } else if (a->cc && cc_op > CC_OP_FLAGS) {
428881de
RH
3698 dst = cpu_cc_dst;
3699 } else {
3700 dst = gen_dest_gpr(dc, a->rd);
3701 }
3702 src1 = gen_load_gpr(dc, a->rs1);
3703
3704 if (a->imm || a->rs2_or_imm == 0) {
3705 if (funci) {
3706 funci(dst, src1, a->rs2_or_imm);
3707 } else {
3708 func(dst, src1, tcg_constant_tl(a->rs2_or_imm));
3709 }
3710 } else {
3711 func(dst, src1, cpu_regs[a->rs2_or_imm]);
3712 }
2a45b736
RH
3713
3714 if (logic_cc) {
3715 if (TARGET_LONG_BITS == 64) {
3716 tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
3717 tcg_gen_movi_tl(cpu_icc_C, 0);
3718 }
3719 tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
3720 tcg_gen_movi_tl(cpu_cc_C, 0);
3721 tcg_gen_movi_tl(cpu_cc_V, 0);
3722 }
3723
428881de
RH
3724 gen_store_gpr(dc, a->rd, dst);
3725
3726 if (a->cc) {
3727 tcg_gen_movi_i32(cpu_cc_op, cc_op);
3728 dc->cc_op = cc_op;
3729 }
3730 return advance_pc(dc);
3731}
3732
3733static bool do_arith(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
3734 void (*func)(TCGv, TCGv, TCGv),
3735 void (*funci)(TCGv, TCGv, target_long),
3736 void (*func_cc)(TCGv, TCGv, TCGv))
3737{
3738 if (a->cc) {
22188d7d 3739 assert(cc_op >= 0);
2a45b736 3740 return do_arith_int(dc, a, cc_op, func_cc, NULL, false);
428881de 3741 }
2a45b736 3742 return do_arith_int(dc, a, cc_op, func, funci, false);
428881de
RH
3743}
3744
3745static bool do_logic(DisasContext *dc, arg_r_r_ri_cc *a,
3746 void (*func)(TCGv, TCGv, TCGv),
3747 void (*funci)(TCGv, TCGv, target_long))
3748{
2a45b736 3749 return do_arith_int(dc, a, CC_OP_FLAGS, func, funci, a->cc);
428881de
RH
3750}
3751
3752TRANS(ADD, ALL, do_arith, a, CC_OP_ADD,
3753 tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_add_cc)
3754TRANS(SUB, ALL, do_arith, a, CC_OP_SUB,
3755 tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_sub_cc)
3756
a9aba13d
RH
3757TRANS(TADDcc, ALL, do_arith, a, CC_OP_TADD, NULL, NULL, gen_op_add_cc)
3758TRANS(TSUBcc, ALL, do_arith, a, CC_OP_TSUB, NULL, NULL, gen_op_sub_cc)
3759TRANS(TADDccTV, ALL, do_arith, a, CC_OP_TADDTV, NULL, NULL, gen_op_taddcctv)
3760TRANS(TSUBccTV, ALL, do_arith, a, CC_OP_TSUBTV, NULL, NULL, gen_op_tsubcctv)
3761
428881de
RH
3762TRANS(AND, ALL, do_logic, a, tcg_gen_and_tl, tcg_gen_andi_tl)
3763TRANS(XOR, ALL, do_logic, a, tcg_gen_xor_tl, tcg_gen_xori_tl)
3764TRANS(ANDN, ALL, do_logic, a, tcg_gen_andc_tl, NULL)
3765TRANS(ORN, ALL, do_logic, a, tcg_gen_orc_tl, NULL)
3766TRANS(XORN, ALL, do_logic, a, tcg_gen_eqv_tl, NULL)
3767
22188d7d 3768TRANS(MULX, 64, do_arith, a, -1, tcg_gen_mul_tl, tcg_gen_muli_tl, NULL)
b5372650
RH
3769TRANS(UMUL, MUL, do_logic, a, gen_op_umul, NULL)
3770TRANS(SMUL, MUL, do_logic, a, gen_op_smul, NULL)
22188d7d 3771
4ee85ea9
RH
3772TRANS(UDIVX, 64, do_arith, a, -1, gen_op_udivx, NULL, NULL)
3773TRANS(SDIVX, 64, do_arith, a, -1, gen_op_sdivx, NULL, NULL)
13260103
RH
3774TRANS(UDIV, DIV, do_arith, a, CC_OP_FLAGS, gen_op_udiv, NULL, gen_op_udivcc)
3775TRANS(SDIV, DIV, do_arith, a, CC_OP_FLAGS, gen_op_sdiv, NULL, gen_op_sdivcc)
4ee85ea9 3776
9c6ec5bc
RH
3777/* TODO: Should have feature bit -- comes in with UltraSparc T2. */
3778TRANS(POPC, 64, do_arith, a, -1, gen_op_popc, NULL, NULL)
3779
428881de
RH
3780static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
3781{
3782 /* OR with %g0 is the canonical alias for MOV. */
3783 if (!a->cc && a->rs1 == 0) {
3784 if (a->imm || a->rs2_or_imm == 0) {
3785 gen_store_gpr(dc, a->rd, tcg_constant_tl(a->rs2_or_imm));
3786 } else if (a->rs2_or_imm & ~0x1f) {
3787 /* For simplicity, we under-decoded the rs2 form. */
3788 return false;
3789 } else {
3790 gen_store_gpr(dc, a->rd, cpu_regs[a->rs2_or_imm]);
3791 }
3792 return advance_pc(dc);
3793 }
3794 return do_logic(dc, a, tcg_gen_or_tl, tcg_gen_ori_tl);
3795}
3796
420a187d
RH
3797static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
3798{
3799 switch (dc->cc_op) {
420a187d
RH
3800 case CC_OP_ADD:
3801 case CC_OP_TADD:
3802 case CC_OP_TADDTV:
3803 return do_arith(dc, a, CC_OP_ADDX,
3804 gen_op_addc_add, NULL, gen_op_addccc_add);
3805 case CC_OP_SUB:
3806 case CC_OP_TSUB:
3807 case CC_OP_TSUBTV:
3808 return do_arith(dc, a, CC_OP_ADDX,
3809 gen_op_addc_sub, NULL, gen_op_addccc_sub);
3810 default:
3811 return do_arith(dc, a, CC_OP_ADDX,
3812 gen_op_addc_generic, NULL, gen_op_addccc_generic);
3813 }
3814}
3815
dfebb950
RH
3816static bool trans_SUBC(DisasContext *dc, arg_r_r_ri_cc *a)
3817{
3818 switch (dc->cc_op) {
dfebb950
RH
3819 case CC_OP_ADD:
3820 case CC_OP_TADD:
3821 case CC_OP_TADDTV:
3822 return do_arith(dc, a, CC_OP_SUBX,
3823 gen_op_subc_add, NULL, gen_op_subccc_add);
3824 case CC_OP_SUB:
3825 case CC_OP_TSUB:
3826 case CC_OP_TSUBTV:
3827 return do_arith(dc, a, CC_OP_SUBX,
3828 gen_op_subc_sub, NULL, gen_op_subccc_sub);
3829 default:
3830 return do_arith(dc, a, CC_OP_SUBX,
3831 gen_op_subc_generic, NULL, gen_op_subccc_generic);
3832 }
3833}
3834
a9aba13d
RH
3835static bool trans_MULScc(DisasContext *dc, arg_r_r_ri_cc *a)
3836{
3837 update_psr(dc);
3838 return do_arith(dc, a, CC_OP_ADD, NULL, NULL, gen_op_mulscc);
3839}
3840
b88ce6f2
RH
3841static bool gen_edge(DisasContext *dc, arg_r_r_r *a,
3842 int width, bool cc, bool left)
3843{
3844 TCGv dst, s1, s2, lo1, lo2;
3845 uint64_t amask, tabl, tabr;
3846 int shift, imask, omask;
3847
3848 dst = gen_dest_gpr(dc, a->rd);
3849 s1 = gen_load_gpr(dc, a->rs1);
3850 s2 = gen_load_gpr(dc, a->rs2);
3851
3852 if (cc) {
3853 tcg_gen_mov_tl(cpu_cc_src, s1);
3854 tcg_gen_mov_tl(cpu_cc_src2, s2);
3855 tcg_gen_sub_tl(cpu_cc_dst, s1, s2);
3856 tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB);
3857 dc->cc_op = CC_OP_SUB;
3858 }
3859
3860 /*
3861 * Theory of operation: there are two tables, left and right (not to
3862 * be confused with the left and right versions of the opcode). These
3863 * are indexed by the low 3 bits of the inputs. To make things "easy",
3864 * these tables are loaded into two constants, TABL and TABR below.
3865 * The operation index = (input & imask) << shift calculates the index
3866 * into the constant, while val = (table >> index) & omask calculates
3867 * the value we're looking for.
3868 */
3869 switch (width) {
3870 case 8:
3871 imask = 0x7;
3872 shift = 3;
3873 omask = 0xff;
3874 if (left) {
3875 tabl = 0x80c0e0f0f8fcfeffULL;
3876 tabr = 0xff7f3f1f0f070301ULL;
3877 } else {
3878 tabl = 0x0103070f1f3f7fffULL;
3879 tabr = 0xfffefcf8f0e0c080ULL;
3880 }
3881 break;
3882 case 16:
3883 imask = 0x6;
3884 shift = 1;
3885 omask = 0xf;
3886 if (left) {
3887 tabl = 0x8cef;
3888 tabr = 0xf731;
3889 } else {
3890 tabl = 0x137f;
3891 tabr = 0xfec8;
3892 }
3893 break;
3894 case 32:
3895 imask = 0x4;
3896 shift = 0;
3897 omask = 0x3;
3898 if (left) {
3899 tabl = (2 << 2) | 3;
3900 tabr = (3 << 2) | 1;
3901 } else {
3902 tabl = (1 << 2) | 3;
3903 tabr = (3 << 2) | 2;
3904 }
3905 break;
3906 default:
3907 abort();
3908 }
3909
3910 lo1 = tcg_temp_new();
3911 lo2 = tcg_temp_new();
3912 tcg_gen_andi_tl(lo1, s1, imask);
3913 tcg_gen_andi_tl(lo2, s2, imask);
3914 tcg_gen_shli_tl(lo1, lo1, shift);
3915 tcg_gen_shli_tl(lo2, lo2, shift);
3916
3917 tcg_gen_shr_tl(lo1, tcg_constant_tl(tabl), lo1);
3918 tcg_gen_shr_tl(lo2, tcg_constant_tl(tabr), lo2);
3919 tcg_gen_andi_tl(lo1, lo1, omask);
3920 tcg_gen_andi_tl(lo2, lo2, omask);
3921
3922 amask = address_mask_i(dc, -8);
3923 tcg_gen_andi_tl(s1, s1, amask);
3924 tcg_gen_andi_tl(s2, s2, amask);
3925
3926 /* Compute dst = (s1 == s2 ? lo1 : lo1 & lo2). */
3927 tcg_gen_and_tl(lo2, lo2, lo1);
3928 tcg_gen_movcond_tl(TCG_COND_EQ, dst, s1, s2, lo1, lo2);
3929
3930 gen_store_gpr(dc, a->rd, dst);
3931 return advance_pc(dc);
3932}
3933
3934TRANS(EDGE8cc, VIS1, gen_edge, a, 8, 1, 0)
3935TRANS(EDGE8Lcc, VIS1, gen_edge, a, 8, 1, 1)
3936TRANS(EDGE16cc, VIS1, gen_edge, a, 16, 1, 0)
3937TRANS(EDGE16Lcc, VIS1, gen_edge, a, 16, 1, 1)
3938TRANS(EDGE32cc, VIS1, gen_edge, a, 32, 1, 0)
3939TRANS(EDGE32Lcc, VIS1, gen_edge, a, 32, 1, 1)
3940
3941TRANS(EDGE8N, VIS2, gen_edge, a, 8, 0, 0)
3942TRANS(EDGE8LN, VIS2, gen_edge, a, 8, 0, 1)
3943TRANS(EDGE16N, VIS2, gen_edge, a, 16, 0, 0)
3944TRANS(EDGE16LN, VIS2, gen_edge, a, 16, 0, 1)
3945TRANS(EDGE32N, VIS2, gen_edge, a, 32, 0, 0)
3946TRANS(EDGE32LN, VIS2, gen_edge, a, 32, 0, 1)
3947
45bfed3b
RH
3948static bool do_rrr(DisasContext *dc, arg_r_r_r *a,
3949 void (*func)(TCGv, TCGv, TCGv))
3950{
3951 TCGv dst = gen_dest_gpr(dc, a->rd);
3952 TCGv src1 = gen_load_gpr(dc, a->rs1);
3953 TCGv src2 = gen_load_gpr(dc, a->rs2);
3954
3955 func(dst, src1, src2);
3956 gen_store_gpr(dc, a->rd, dst);
3957 return advance_pc(dc);
3958}
3959
3960TRANS(ARRAY8, VIS1, do_rrr, a, gen_helper_array8)
3961TRANS(ARRAY16, VIS1, do_rrr, a, gen_op_array16)
3962TRANS(ARRAY32, VIS1, do_rrr, a, gen_op_array32)
3963
9e20ca94
RH
3964static void gen_op_alignaddr(TCGv dst, TCGv s1, TCGv s2)
3965{
3966#ifdef TARGET_SPARC64
3967 TCGv tmp = tcg_temp_new();
3968
3969 tcg_gen_add_tl(tmp, s1, s2);
3970 tcg_gen_andi_tl(dst, tmp, -8);
3971 tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3);
3972#else
3973 g_assert_not_reached();
3974#endif
3975}
3976
3977static void gen_op_alignaddrl(TCGv dst, TCGv s1, TCGv s2)
3978{
3979#ifdef TARGET_SPARC64
3980 TCGv tmp = tcg_temp_new();
3981
3982 tcg_gen_add_tl(tmp, s1, s2);
3983 tcg_gen_andi_tl(dst, tmp, -8);
3984 tcg_gen_neg_tl(tmp, tmp);
3985 tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3);
3986#else
3987 g_assert_not_reached();
3988#endif
3989}
3990
3991TRANS(ALIGNADDR, VIS1, do_rrr, a, gen_op_alignaddr)
3992TRANS(ALIGNADDRL, VIS1, do_rrr, a, gen_op_alignaddrl)
3993
39ca3490
RH
3994static void gen_op_bmask(TCGv dst, TCGv s1, TCGv s2)
3995{
3996#ifdef TARGET_SPARC64
3997 tcg_gen_add_tl(dst, s1, s2);
3998 tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, dst, 32, 32);
3999#else
4000 g_assert_not_reached();
4001#endif
4002}
4003
4004TRANS(BMASK, VIS2, do_rrr, a, gen_op_bmask)
4005
5fc546ee
RH
4006static bool do_shift_r(DisasContext *dc, arg_shiftr *a, bool l, bool u)
4007{
4008 TCGv dst, src1, src2;
4009
4010 /* Reject 64-bit shifts for sparc32. */
4011 if (avail_32(dc) && a->x) {
4012 return false;
4013 }
4014
4015 src2 = tcg_temp_new();
4016 tcg_gen_andi_tl(src2, gen_load_gpr(dc, a->rs2), a->x ? 63 : 31);
4017 src1 = gen_load_gpr(dc, a->rs1);
4018 dst = gen_dest_gpr(dc, a->rd);
4019
4020 if (l) {
4021 tcg_gen_shl_tl(dst, src1, src2);
4022 if (!a->x) {
4023 tcg_gen_ext32u_tl(dst, dst);
4024 }
4025 } else if (u) {
4026 if (!a->x) {
4027 tcg_gen_ext32u_tl(dst, src1);
4028 src1 = dst;
4029 }
4030 tcg_gen_shr_tl(dst, src1, src2);
4031 } else {
4032 if (!a->x) {
4033 tcg_gen_ext32s_tl(dst, src1);
4034 src1 = dst;
4035 }
4036 tcg_gen_sar_tl(dst, src1, src2);
4037 }
4038 gen_store_gpr(dc, a->rd, dst);
4039 return advance_pc(dc);
4040}
4041
4042TRANS(SLL_r, ALL, do_shift_r, a, true, true)
4043TRANS(SRL_r, ALL, do_shift_r, a, false, true)
4044TRANS(SRA_r, ALL, do_shift_r, a, false, false)
4045
4046static bool do_shift_i(DisasContext *dc, arg_shifti *a, bool l, bool u)
4047{
4048 TCGv dst, src1;
4049
4050 /* Reject 64-bit shifts for sparc32. */
4051 if (avail_32(dc) && (a->x || a->i >= 32)) {
4052 return false;
4053 }
4054
4055 src1 = gen_load_gpr(dc, a->rs1);
4056 dst = gen_dest_gpr(dc, a->rd);
4057
4058 if (avail_32(dc) || a->x) {
4059 if (l) {
4060 tcg_gen_shli_tl(dst, src1, a->i);
4061 } else if (u) {
4062 tcg_gen_shri_tl(dst, src1, a->i);
4063 } else {
4064 tcg_gen_sari_tl(dst, src1, a->i);
4065 }
4066 } else {
4067 if (l) {
4068 tcg_gen_deposit_z_tl(dst, src1, a->i, 32 - a->i);
4069 } else if (u) {
4070 tcg_gen_extract_tl(dst, src1, a->i, 32 - a->i);
4071 } else {
4072 tcg_gen_sextract_tl(dst, src1, a->i, 32 - a->i);
4073 }
4074 }
4075 gen_store_gpr(dc, a->rd, dst);
4076 return advance_pc(dc);
4077}
4078
4079TRANS(SLL_i, ALL, do_shift_i, a, true, true)
4080TRANS(SRL_i, ALL, do_shift_i, a, false, true)
4081TRANS(SRA_i, ALL, do_shift_i, a, false, false)
4082
fb4ed7aa
RH
4083static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
4084{
4085 /* For simplicity, we under-decoded the rs2 form. */
4086 if (!imm && rs2_or_imm & ~0x1f) {
4087 return NULL;
4088 }
4089 if (imm || rs2_or_imm == 0) {
4090 return tcg_constant_tl(rs2_or_imm);
4091 } else {
4092 return cpu_regs[rs2_or_imm];
4093 }
4094}
4095
4096static bool do_mov_cond(DisasContext *dc, DisasCompare *cmp, int rd, TCGv src2)
4097{
4098 TCGv dst = gen_load_gpr(dc, rd);
4099
4100 tcg_gen_movcond_tl(cmp->cond, dst, cmp->c1, cmp->c2, src2, dst);
4101 gen_store_gpr(dc, rd, dst);
4102 return advance_pc(dc);
4103}
4104
4105static bool trans_MOVcc(DisasContext *dc, arg_MOVcc *a)
4106{
4107 TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
4108 DisasCompare cmp;
4109
4110 if (src2 == NULL) {
4111 return false;
4112 }
4113 gen_compare(&cmp, a->cc, a->cond, dc);
4114 return do_mov_cond(dc, &cmp, a->rd, src2);
4115}
4116
4117static bool trans_MOVfcc(DisasContext *dc, arg_MOVfcc *a)
4118{
4119 TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
4120 DisasCompare cmp;
4121
4122 if (src2 == NULL) {
4123 return false;
4124 }
4125 gen_fcompare(&cmp, a->cc, a->cond);
4126 return do_mov_cond(dc, &cmp, a->rd, src2);
4127}
4128
4129static bool trans_MOVR(DisasContext *dc, arg_MOVR *a)
4130{
4131 TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
4132 DisasCompare cmp;
4133
4134 if (src2 == NULL) {
4135 return false;
4136 }
4137 gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
4138 return do_mov_cond(dc, &cmp, a->rd, src2);
4139}
4140
86b82fe0
RH
4141static bool do_add_special(DisasContext *dc, arg_r_r_ri *a,
4142 bool (*func)(DisasContext *dc, int rd, TCGv src))
4143{
4144 TCGv src1, sum;
4145
4146 /* For simplicity, we under-decoded the rs2 form. */
4147 if (!a->imm && a->rs2_or_imm & ~0x1f) {
4148 return false;
4149 }
4150
4151 /*
4152 * Always load the sum into a new temporary.
4153 * This is required to capture the value across a window change,
4154 * e.g. SAVE and RESTORE, and may be optimized away otherwise.
4155 */
4156 sum = tcg_temp_new();
4157 src1 = gen_load_gpr(dc, a->rs1);
4158 if (a->imm || a->rs2_or_imm == 0) {
4159 tcg_gen_addi_tl(sum, src1, a->rs2_or_imm);
4160 } else {
4161 tcg_gen_add_tl(sum, src1, cpu_regs[a->rs2_or_imm]);
4162 }
4163 return func(dc, a->rd, sum);
4164}
4165
4166static bool do_jmpl(DisasContext *dc, int rd, TCGv src)
4167{
4168 /*
4169 * Preserve pc across advance, so that we can delay
4170 * the writeback to rd until after src is consumed.
4171 */
4172 target_ulong cur_pc = dc->pc;
4173
4174 gen_check_align(dc, src, 3);
4175
4176 gen_mov_pc_npc(dc);
4177 tcg_gen_mov_tl(cpu_npc, src);
4178 gen_address_mask(dc, cpu_npc);
4179 gen_store_gpr(dc, rd, tcg_constant_tl(cur_pc));
4180
4181 dc->npc = DYNAMIC_PC_LOOKUP;
4182 return true;
4183}
4184
4185TRANS(JMPL, ALL, do_add_special, a, do_jmpl)
4186
4187static bool do_rett(DisasContext *dc, int rd, TCGv src)
4188{
4189 if (!supervisor(dc)) {
4190 return raise_priv(dc);
4191 }
4192
4193 gen_check_align(dc, src, 3);
4194
4195 gen_mov_pc_npc(dc);
4196 tcg_gen_mov_tl(cpu_npc, src);
4197 gen_helper_rett(tcg_env);
4198
4199 dc->npc = DYNAMIC_PC;
4200 return true;
4201}
4202
4203TRANS(RETT, 32, do_add_special, a, do_rett)
4204
4205static bool do_return(DisasContext *dc, int rd, TCGv src)
4206{
4207 gen_check_align(dc, src, 3);
4208
4209 gen_mov_pc_npc(dc);
4210 tcg_gen_mov_tl(cpu_npc, src);
4211 gen_address_mask(dc, cpu_npc);
4212
4213 gen_helper_restore(tcg_env);
4214 dc->npc = DYNAMIC_PC_LOOKUP;
4215 return true;
4216}
4217
4218TRANS(RETURN, 64, do_add_special, a, do_return)
4219
d3825800
RH
4220static bool do_save(DisasContext *dc, int rd, TCGv src)
4221{
4222 gen_helper_save(tcg_env);
4223 gen_store_gpr(dc, rd, src);
4224 return advance_pc(dc);
4225}
4226
4227TRANS(SAVE, ALL, do_add_special, a, do_save)
4228
4229static bool do_restore(DisasContext *dc, int rd, TCGv src)
4230{
4231 gen_helper_restore(tcg_env);
4232 gen_store_gpr(dc, rd, src);
4233 return advance_pc(dc);
4234}
4235
4236TRANS(RESTORE, ALL, do_add_special, a, do_restore)
4237
8f75b8a4
RH
4238static bool do_done_retry(DisasContext *dc, bool done)
4239{
4240 if (!supervisor(dc)) {
4241 return raise_priv(dc);
4242 }
4243 dc->npc = DYNAMIC_PC;
4244 dc->pc = DYNAMIC_PC;
4245 translator_io_start(&dc->base);
4246 if (done) {
4247 gen_helper_done(tcg_env);
4248 } else {
4249 gen_helper_retry(tcg_env);
4250 }
4251 return true;
4252}
4253
4254TRANS(DONE, 64, do_done_retry, true)
4255TRANS(RETRY, 64, do_done_retry, false)
4256
0880d20b
RH
4257/*
4258 * Major opcode 11 -- load and store instructions
4259 */
4260
4261static TCGv gen_ldst_addr(DisasContext *dc, int rs1, bool imm, int rs2_or_imm)
4262{
4263 TCGv addr, tmp = NULL;
4264
4265 /* For simplicity, we under-decoded the rs2 form. */
4266 if (!imm && rs2_or_imm & ~0x1f) {
4267 return NULL;
4268 }
4269
4270 addr = gen_load_gpr(dc, rs1);
4271 if (rs2_or_imm) {
4272 tmp = tcg_temp_new();
4273 if (imm) {
4274 tcg_gen_addi_tl(tmp, addr, rs2_or_imm);
4275 } else {
4276 tcg_gen_add_tl(tmp, addr, cpu_regs[rs2_or_imm]);
4277 }
4278 addr = tmp;
4279 }
4280 if (AM_CHECK(dc)) {
4281 if (!tmp) {
4282 tmp = tcg_temp_new();
4283 }
4284 tcg_gen_ext32u_tl(tmp, addr);
4285 addr = tmp;
4286 }
4287 return addr;
4288}
4289
4290static bool do_ld_gpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
4291{
4292 TCGv reg, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4293 DisasASI da;
4294
4295 if (addr == NULL) {
4296 return false;
4297 }
4298 da = resolve_asi(dc, a->asi, mop);
4299
4300 reg = gen_dest_gpr(dc, a->rd);
42071fc1 4301 gen_ld_asi(dc, &da, reg, addr);
0880d20b
RH
4302 gen_store_gpr(dc, a->rd, reg);
4303 return advance_pc(dc);
4304}
4305
4306TRANS(LDUW, ALL, do_ld_gpr, a, MO_TEUL)
4307TRANS(LDUB, ALL, do_ld_gpr, a, MO_UB)
4308TRANS(LDUH, ALL, do_ld_gpr, a, MO_TEUW)
4309TRANS(LDSB, ALL, do_ld_gpr, a, MO_SB)
4310TRANS(LDSH, ALL, do_ld_gpr, a, MO_TESW)
4311TRANS(LDSW, 64, do_ld_gpr, a, MO_TESL)
4312TRANS(LDX, 64, do_ld_gpr, a, MO_TEUQ)
4313
4314static bool do_st_gpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
4315{
4316 TCGv reg, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4317 DisasASI da;
4318
4319 if (addr == NULL) {
4320 return false;
4321 }
4322 da = resolve_asi(dc, a->asi, mop);
4323
4324 reg = gen_load_gpr(dc, a->rd);
42071fc1 4325 gen_st_asi(dc, &da, reg, addr);
0880d20b
RH
4326 return advance_pc(dc);
4327}
4328
4329TRANS(STW, ALL, do_st_gpr, a, MO_TEUL)
4330TRANS(STB, ALL, do_st_gpr, a, MO_UB)
4331TRANS(STH, ALL, do_st_gpr, a, MO_TEUW)
4332TRANS(STX, 64, do_st_gpr, a, MO_TEUQ)
4333
4334static bool trans_LDD(DisasContext *dc, arg_r_r_ri_asi *a)
4335{
4336 TCGv addr;
4337 DisasASI da;
4338
4339 if (a->rd & 1) {
4340 return false;
4341 }
4342 addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4343 if (addr == NULL) {
4344 return false;
4345 }
4346 da = resolve_asi(dc, a->asi, MO_TEUQ);
42071fc1 4347 gen_ldda_asi(dc, &da, addr, a->rd);
0880d20b
RH
4348 return advance_pc(dc);
4349}
4350
4351static bool trans_STD(DisasContext *dc, arg_r_r_ri_asi *a)
4352{
4353 TCGv addr;
4354 DisasASI da;
4355
4356 if (a->rd & 1) {
4357 return false;
4358 }
4359 addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4360 if (addr == NULL) {
4361 return false;
4362 }
4363 da = resolve_asi(dc, a->asi, MO_TEUQ);
42071fc1 4364 gen_stda_asi(dc, &da, addr, a->rd);
0880d20b
RH
4365 return advance_pc(dc);
4366}
4367
cf07cd1e
RH
4368static bool trans_LDSTUB(DisasContext *dc, arg_r_r_ri_asi *a)
4369{
4370 TCGv addr, reg;
4371 DisasASI da;
4372
4373 addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4374 if (addr == NULL) {
4375 return false;
4376 }
4377 da = resolve_asi(dc, a->asi, MO_UB);
4378
4379 reg = gen_dest_gpr(dc, a->rd);
4380 gen_ldstub_asi(dc, &da, reg, addr);
4381 gen_store_gpr(dc, a->rd, reg);
4382 return advance_pc(dc);
4383}
4384
dca544b9
RH
4385static bool trans_SWAP(DisasContext *dc, arg_r_r_ri_asi *a)
4386{
4387 TCGv addr, dst, src;
4388 DisasASI da;
4389
4390 addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4391 if (addr == NULL) {
4392 return false;
4393 }
4394 da = resolve_asi(dc, a->asi, MO_TEUL);
4395
4396 dst = gen_dest_gpr(dc, a->rd);
4397 src = gen_load_gpr(dc, a->rd);
4398 gen_swap_asi(dc, &da, dst, src, addr);
4399 gen_store_gpr(dc, a->rd, dst);
4400 return advance_pc(dc);
4401}
4402
d0a11d25
RH
4403static bool do_casa(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
4404{
4405 TCGv addr, o, n, c;
4406 DisasASI da;
4407
4408 addr = gen_ldst_addr(dc, a->rs1, true, 0);
4409 if (addr == NULL) {
4410 return false;
4411 }
4412 da = resolve_asi(dc, a->asi, mop);
4413
4414 o = gen_dest_gpr(dc, a->rd);
4415 n = gen_load_gpr(dc, a->rd);
4416 c = gen_load_gpr(dc, a->rs2_or_imm);
4417 gen_cas_asi(dc, &da, o, n, c, addr);
4418 gen_store_gpr(dc, a->rd, o);
4419 return advance_pc(dc);
4420}
4421
4422TRANS(CASA, CASA, do_casa, a, MO_TEUL)
4423TRANS(CASXA, 64, do_casa, a, MO_TEUQ)
4424
06c060d9
RH
4425static bool do_ld_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
4426{
4427 TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4428 DisasASI da;
4429
4430 if (addr == NULL) {
4431 return false;
4432 }
4433 if (gen_trap_ifnofpu(dc)) {
4434 return true;
4435 }
4436 if (sz == MO_128 && gen_trap_float128(dc)) {
4437 return true;
4438 }
4439 da = resolve_asi(dc, a->asi, MO_TE | sz);
287b1152 4440 gen_ldf_asi(dc, &da, sz, addr, a->rd);
06c060d9
RH
4441 gen_update_fprs_dirty(dc, a->rd);
4442 return advance_pc(dc);
4443}
4444
4445TRANS(LDF, ALL, do_ld_fpr, a, MO_32)
4446TRANS(LDDF, ALL, do_ld_fpr, a, MO_64)
4447TRANS(LDQF, ALL, do_ld_fpr, a, MO_128)
4448
287b1152
RH
4449TRANS(LDFA, 64, do_ld_fpr, a, MO_32)
4450TRANS(LDDFA, 64, do_ld_fpr, a, MO_64)
4451TRANS(LDQFA, 64, do_ld_fpr, a, MO_128)
4452
06c060d9
RH
4453static bool do_st_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
4454{
4455 TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4456 DisasASI da;
4457
4458 if (addr == NULL) {
4459 return false;
4460 }
4461 if (gen_trap_ifnofpu(dc)) {
4462 return true;
4463 }
4464 if (sz == MO_128 && gen_trap_float128(dc)) {
4465 return true;
4466 }
4467 da = resolve_asi(dc, a->asi, MO_TE | sz);
287b1152 4468 gen_stf_asi(dc, &da, sz, addr, a->rd);
06c060d9
RH
4469 return advance_pc(dc);
4470}
4471
4472TRANS(STF, ALL, do_st_fpr, a, MO_32)
4473TRANS(STDF, ALL, do_st_fpr, a, MO_64)
4474TRANS(STQF, ALL, do_st_fpr, a, MO_128)
4475
287b1152
RH
4476TRANS(STFA, 64, do_st_fpr, a, MO_32)
4477TRANS(STDFA, 64, do_st_fpr, a, MO_64)
4478TRANS(STQFA, 64, do_st_fpr, a, MO_128)
4479
06c060d9
RH
4480static bool trans_STDFQ(DisasContext *dc, arg_STDFQ *a)
4481{
4482 if (!avail_32(dc)) {
4483 return false;
4484 }
4485 if (!supervisor(dc)) {
4486 return raise_priv(dc);
4487 }
4488 if (gen_trap_ifnofpu(dc)) {
4489 return true;
4490 }
4491 gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
4492 return true;
4493}
4494
da681406
RH
4495static bool do_ldfsr(DisasContext *dc, arg_r_r_ri *a, MemOp mop,
4496 target_ulong new_mask, target_ulong old_mask)
3d3c0673 4497{
da681406 4498 TCGv tmp, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
3d3c0673
RH
4499 if (addr == NULL) {
4500 return false;
4501 }
4502 if (gen_trap_ifnofpu(dc)) {
4503 return true;
4504 }
da681406
RH
4505 tmp = tcg_temp_new();
4506 tcg_gen_qemu_ld_tl(tmp, addr, dc->mem_idx, mop | MO_ALIGN);
4507 tcg_gen_andi_tl(tmp, tmp, new_mask);
4508 tcg_gen_andi_tl(cpu_fsr, cpu_fsr, old_mask);
4509 tcg_gen_or_tl(cpu_fsr, cpu_fsr, tmp);
4510 gen_helper_set_fsr(tcg_env, cpu_fsr);
3d3c0673
RH
4511 return advance_pc(dc);
4512}
4513
da681406
RH
4514TRANS(LDFSR, ALL, do_ldfsr, a, MO_TEUL, FSR_LDFSR_MASK, FSR_LDFSR_OLDMASK)
4515TRANS(LDXFSR, 64, do_ldfsr, a, MO_TEUQ, FSR_LDXFSR_MASK, FSR_LDXFSR_OLDMASK)
3d3c0673
RH
4516
4517static bool do_stfsr(DisasContext *dc, arg_r_r_ri *a, MemOp mop)
4518{
4519 TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4520 if (addr == NULL) {
4521 return false;
4522 }
4523 if (gen_trap_ifnofpu(dc)) {
4524 return true;
4525 }
4526 tcg_gen_qemu_st_tl(cpu_fsr, addr, dc->mem_idx, mop | MO_ALIGN);
4527 return advance_pc(dc);
4528}
4529
4530TRANS(STFSR, ALL, do_stfsr, a, MO_TEUL)
4531TRANS(STXFSR, 64, do_stfsr, a, MO_TEUQ)
4532
3a38260e
RH
4533static bool do_fc(DisasContext *dc, int rd, bool c)
4534{
4535 uint64_t mask;
4536
4537 if (gen_trap_ifnofpu(dc)) {
4538 return true;
4539 }
4540
4541 if (rd & 1) {
4542 mask = MAKE_64BIT_MASK(0, 32);
4543 } else {
4544 mask = MAKE_64BIT_MASK(32, 32);
4545 }
4546 if (c) {
4547 tcg_gen_ori_i64(cpu_fpr[rd / 2], cpu_fpr[rd / 2], mask);
4548 } else {
4549 tcg_gen_andi_i64(cpu_fpr[rd / 2], cpu_fpr[rd / 2], ~mask);
4550 }
4551 gen_update_fprs_dirty(dc, rd);
4552 return advance_pc(dc);
4553}
4554
4555TRANS(FZEROs, VIS1, do_fc, a->rd, 0)
4556TRANS(FONEs, VIS1, do_fc, a->rd, 1)
4557
4558static bool do_dc(DisasContext *dc, int rd, int64_t c)
4559{
4560 if (gen_trap_ifnofpu(dc)) {
4561 return true;
4562 }
4563
4564 tcg_gen_movi_i64(cpu_fpr[rd / 2], c);
4565 gen_update_fprs_dirty(dc, rd);
4566 return advance_pc(dc);
4567}
4568
4569TRANS(FZEROd, VIS1, do_dc, a->rd, 0)
4570TRANS(FONEd, VIS1, do_dc, a->rd, -1)
4571
baf3dbf2
RH
4572static bool do_ff(DisasContext *dc, arg_r_r *a,
4573 void (*func)(TCGv_i32, TCGv_i32))
4574{
4575 TCGv_i32 tmp;
4576
4577 if (gen_trap_ifnofpu(dc)) {
4578 return true;
4579 }
4580
4581 tmp = gen_load_fpr_F(dc, a->rs);
4582 func(tmp, tmp);
4583 gen_store_fpr_F(dc, a->rd, tmp);
4584 return advance_pc(dc);
4585}
4586
4587TRANS(FMOVs, ALL, do_ff, a, gen_op_fmovs)
4588TRANS(FNEGs, ALL, do_ff, a, gen_op_fnegs)
4589TRANS(FABSs, ALL, do_ff, a, gen_op_fabss)
4590TRANS(FSRCs, VIS1, do_ff, a, tcg_gen_mov_i32)
4591TRANS(FNOTs, VIS1, do_ff, a, tcg_gen_not_i32)
4592
2f722641
RH
4593static bool do_fd(DisasContext *dc, arg_r_r *a,
4594 void (*func)(TCGv_i32, TCGv_i64))
4595{
4596 TCGv_i32 dst;
4597 TCGv_i64 src;
4598
4599 if (gen_trap_ifnofpu(dc)) {
4600 return true;
4601 }
4602
4603 dst = gen_dest_fpr_F(dc);
4604 src = gen_load_fpr_D(dc, a->rs);
4605 func(dst, src);
4606 gen_store_fpr_F(dc, a->rd, dst);
4607 return advance_pc(dc);
4608}
4609
4610TRANS(FPACK16, VIS1, do_fd, a, gen_op_fpack16)
4611TRANS(FPACKFIX, VIS1, do_fd, a, gen_op_fpackfix)
4612
119cb94f
RH
4613static bool do_env_ff(DisasContext *dc, arg_r_r *a,
4614 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
4615{
4616 TCGv_i32 tmp;
4617
4618 if (gen_trap_ifnofpu(dc)) {
4619 return true;
4620 }
4621
4622 gen_op_clear_ieee_excp_and_FTT();
4623 tmp = gen_load_fpr_F(dc, a->rs);
4624 func(tmp, tcg_env, tmp);
4625 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4626 gen_store_fpr_F(dc, a->rd, tmp);
4627 return advance_pc(dc);
4628}
4629
4630TRANS(FSQRTs, ALL, do_env_ff, a, gen_helper_fsqrts)
4631TRANS(FiTOs, ALL, do_env_ff, a, gen_helper_fitos)
4632TRANS(FsTOi, ALL, do_env_ff, a, gen_helper_fstoi)
4633
8c94bcd8
RH
4634static bool do_env_fd(DisasContext *dc, arg_r_r *a,
4635 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
4636{
4637 TCGv_i32 dst;
4638 TCGv_i64 src;
4639
4640 if (gen_trap_ifnofpu(dc)) {
4641 return true;
4642 }
4643
4644 gen_op_clear_ieee_excp_and_FTT();
4645 dst = gen_dest_fpr_F(dc);
4646 src = gen_load_fpr_D(dc, a->rs);
4647 func(dst, tcg_env, src);
4648 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4649 gen_store_fpr_F(dc, a->rd, dst);
4650 return advance_pc(dc);
4651}
4652
4653TRANS(FdTOs, ALL, do_env_fd, a, gen_helper_fdtos)
4654TRANS(FdTOi, ALL, do_env_fd, a, gen_helper_fdtoi)
4655TRANS(FxTOs, 64, do_env_fd, a, gen_helper_fxtos)
4656
c6d83e4f
RH
4657static bool do_dd(DisasContext *dc, arg_r_r *a,
4658 void (*func)(TCGv_i64, TCGv_i64))
4659{
4660 TCGv_i64 dst, src;
4661
4662 if (gen_trap_ifnofpu(dc)) {
4663 return true;
4664 }
4665
4666 dst = gen_dest_fpr_D(dc, a->rd);
4667 src = gen_load_fpr_D(dc, a->rs);
4668 func(dst, src);
4669 gen_store_fpr_D(dc, a->rd, dst);
4670 return advance_pc(dc);
4671}
4672
4673TRANS(FMOVd, 64, do_dd, a, gen_op_fmovd)
4674TRANS(FNEGd, 64, do_dd, a, gen_op_fnegd)
4675TRANS(FABSd, 64, do_dd, a, gen_op_fabsd)
4676TRANS(FSRCd, VIS1, do_dd, a, tcg_gen_mov_i64)
4677TRANS(FNOTd, VIS1, do_dd, a, tcg_gen_not_i64)
4678
8aa418b3
RH
4679static bool do_env_dd(DisasContext *dc, arg_r_r *a,
4680 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
4681{
4682 TCGv_i64 dst, src;
4683
4684 if (gen_trap_ifnofpu(dc)) {
4685 return true;
4686 }
4687
4688 gen_op_clear_ieee_excp_and_FTT();
4689 dst = gen_dest_fpr_D(dc, a->rd);
4690 src = gen_load_fpr_D(dc, a->rs);
4691 func(dst, tcg_env, src);
4692 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4693 gen_store_fpr_D(dc, a->rd, dst);
4694 return advance_pc(dc);
4695}
4696
4697TRANS(FSQRTd, ALL, do_env_dd, a, gen_helper_fsqrtd)
4698TRANS(FxTOd, 64, do_env_dd, a, gen_helper_fxtod)
4699TRANS(FdTOx, 64, do_env_dd, a, gen_helper_fdtox)
4700
199d43ef
RH
4701static bool do_env_df(DisasContext *dc, arg_r_r *a,
4702 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
4703{
4704 TCGv_i64 dst;
4705 TCGv_i32 src;
4706
4707 if (gen_trap_ifnofpu(dc)) {
4708 return true;
4709 }
4710
4711 gen_op_clear_ieee_excp_and_FTT();
4712 dst = gen_dest_fpr_D(dc, a->rd);
4713 src = gen_load_fpr_F(dc, a->rs);
4714 func(dst, tcg_env, src);
4715 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4716 gen_store_fpr_D(dc, a->rd, dst);
4717 return advance_pc(dc);
4718}
4719
4720TRANS(FiTOd, ALL, do_env_df, a, gen_helper_fitod)
4721TRANS(FsTOd, ALL, do_env_df, a, gen_helper_fstod)
4722TRANS(FsTOx, 64, do_env_df, a, gen_helper_fstox)
4723
f4e18df5
RH
4724static bool trans_FMOVq(DisasContext *dc, arg_FMOVq *a)
4725{
4726 int rd, rs;
4727
4728 if (!avail_64(dc)) {
4729 return false;
4730 }
4731 if (gen_trap_ifnofpu(dc)) {
4732 return true;
4733 }
4734 if (gen_trap_float128(dc)) {
4735 return true;
4736 }
4737
4738 gen_op_clear_ieee_excp_and_FTT();
4739 rd = QFPREG(a->rd);
4740 rs = QFPREG(a->rs);
4741 tcg_gen_mov_i64(cpu_fpr[rd / 2], cpu_fpr[rs / 2]);
4742 tcg_gen_mov_i64(cpu_fpr[rd / 2 + 1], cpu_fpr[rs / 2 + 1]);
4743 gen_update_fprs_dirty(dc, rd);
4744 return advance_pc(dc);
4745}
4746
4747static bool do_qq(DisasContext *dc, arg_r_r *a,
4748 void (*func)(TCGv_env))
4749{
4750 if (gen_trap_ifnofpu(dc)) {
4751 return true;
4752 }
4753 if (gen_trap_float128(dc)) {
4754 return true;
4755 }
4756
4757 gen_op_clear_ieee_excp_and_FTT();
4758 gen_op_load_fpr_QT1(QFPREG(a->rs));
4759 func(tcg_env);
4760 gen_op_store_QT0_fpr(QFPREG(a->rd));
4761 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4762 return advance_pc(dc);
4763}
4764
4765TRANS(FNEGq, 64, do_qq, a, gen_helper_fnegq)
4766TRANS(FABSq, 64, do_qq, a, gen_helper_fabsq)
4767
c995216b
RH
4768static bool do_env_qq(DisasContext *dc, arg_r_r *a,
4769 void (*func)(TCGv_env))
4770{
4771 if (gen_trap_ifnofpu(dc)) {
4772 return true;
4773 }
4774 if (gen_trap_float128(dc)) {
4775 return true;
4776 }
4777
4778 gen_op_clear_ieee_excp_and_FTT();
4779 gen_op_load_fpr_QT1(QFPREG(a->rs));
4780 func(tcg_env);
4781 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4782 gen_op_store_QT0_fpr(QFPREG(a->rd));
4783 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4784 return advance_pc(dc);
4785}
4786
4787TRANS(FSQRTq, ALL, do_env_qq, a, gen_helper_fsqrtq)
4788
bd9c5c42
RH
4789static bool do_env_fq(DisasContext *dc, arg_r_r *a,
4790 void (*func)(TCGv_i32, TCGv_env))
4791{
4792 TCGv_i32 dst;
4793
4794 if (gen_trap_ifnofpu(dc)) {
4795 return true;
4796 }
4797 if (gen_trap_float128(dc)) {
4798 return true;
4799 }
4800
4801 gen_op_clear_ieee_excp_and_FTT();
4802 gen_op_load_fpr_QT1(QFPREG(a->rs));
4803 dst = gen_dest_fpr_F(dc);
4804 func(dst, tcg_env);
4805 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4806 gen_store_fpr_F(dc, a->rd, dst);
4807 return advance_pc(dc);
4808}
4809
4810TRANS(FqTOs, ALL, do_env_fq, a, gen_helper_fqtos)
4811TRANS(FqTOi, ALL, do_env_fq, a, gen_helper_fqtoi)
4812
1617586f
RH
4813static bool do_env_dq(DisasContext *dc, arg_r_r *a,
4814 void (*func)(TCGv_i64, TCGv_env))
4815{
4816 TCGv_i64 dst;
4817
4818 if (gen_trap_ifnofpu(dc)) {
4819 return true;
4820 }
4821 if (gen_trap_float128(dc)) {
4822 return true;
4823 }
4824
4825 gen_op_clear_ieee_excp_and_FTT();
4826 gen_op_load_fpr_QT1(QFPREG(a->rs));
4827 dst = gen_dest_fpr_D(dc, a->rd);
4828 func(dst, tcg_env);
4829 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4830 gen_store_fpr_D(dc, a->rd, dst);
4831 return advance_pc(dc);
4832}
4833
4834TRANS(FqTOd, ALL, do_env_dq, a, gen_helper_fqtod)
4835TRANS(FqTOx, 64, do_env_dq, a, gen_helper_fqtox)
4836
13ebcc77
RH
4837static bool do_env_qf(DisasContext *dc, arg_r_r *a,
4838 void (*func)(TCGv_env, TCGv_i32))
4839{
4840 TCGv_i32 src;
4841
4842 if (gen_trap_ifnofpu(dc)) {
4843 return true;
4844 }
4845 if (gen_trap_float128(dc)) {
4846 return true;
4847 }
4848
4849 gen_op_clear_ieee_excp_and_FTT();
4850 src = gen_load_fpr_F(dc, a->rs);
4851 func(tcg_env, src);
4852 gen_op_store_QT0_fpr(QFPREG(a->rd));
4853 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4854 return advance_pc(dc);
4855}
4856
4857TRANS(FiTOq, ALL, do_env_qf, a, gen_helper_fitoq)
4858TRANS(FsTOq, ALL, do_env_qf, a, gen_helper_fstoq)
4859
7b8e3e1a
RH
4860static bool do_env_qd(DisasContext *dc, arg_r_r *a,
4861 void (*func)(TCGv_env, TCGv_i64))
4862{
4863 TCGv_i64 src;
4864
4865 if (gen_trap_ifnofpu(dc)) {
4866 return true;
4867 }
4868 if (gen_trap_float128(dc)) {
4869 return true;
4870 }
4871
4872 gen_op_clear_ieee_excp_and_FTT();
4873 src = gen_load_fpr_D(dc, a->rs);
4874 func(tcg_env, src);
4875 gen_op_store_QT0_fpr(QFPREG(a->rd));
4876 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4877 return advance_pc(dc);
4878}
4879
4880TRANS(FdTOq, ALL, do_env_qd, a, gen_helper_fdtoq)
4881TRANS(FxTOq, 64, do_env_qd, a, gen_helper_fxtoq)
4882
7f10b52f
RH
4883static bool do_fff(DisasContext *dc, arg_r_r_r *a,
4884 void (*func)(TCGv_i32, TCGv_i32, TCGv_i32))
4885{
4886 TCGv_i32 src1, src2;
4887
4888 if (gen_trap_ifnofpu(dc)) {
4889 return true;
4890 }
4891
4892 src1 = gen_load_fpr_F(dc, a->rs1);
4893 src2 = gen_load_fpr_F(dc, a->rs2);
4894 func(src1, src1, src2);
4895 gen_store_fpr_F(dc, a->rd, src1);
4896 return advance_pc(dc);
4897}
4898
4899TRANS(FPADD16s, VIS1, do_fff, a, tcg_gen_vec_add16_i32)
4900TRANS(FPADD32s, VIS1, do_fff, a, tcg_gen_add_i32)
4901TRANS(FPSUB16s, VIS1, do_fff, a, tcg_gen_vec_sub16_i32)
4902TRANS(FPSUB32s, VIS1, do_fff, a, tcg_gen_sub_i32)
4903TRANS(FNORs, VIS1, do_fff, a, tcg_gen_nor_i32)
4904TRANS(FANDNOTs, VIS1, do_fff, a, tcg_gen_andc_i32)
4905TRANS(FXORs, VIS1, do_fff, a, tcg_gen_xor_i32)
4906TRANS(FNANDs, VIS1, do_fff, a, tcg_gen_nand_i32)
4907TRANS(FANDs, VIS1, do_fff, a, tcg_gen_and_i32)
4908TRANS(FXNORs, VIS1, do_fff, a, tcg_gen_eqv_i32)
4909TRANS(FORNOTs, VIS1, do_fff, a, tcg_gen_orc_i32)
4910TRANS(FORs, VIS1, do_fff, a, tcg_gen_or_i32)
4911
c1514961
RH
4912static bool do_env_fff(DisasContext *dc, arg_r_r_r *a,
4913 void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
4914{
4915 TCGv_i32 src1, src2;
4916
4917 if (gen_trap_ifnofpu(dc)) {
4918 return true;
4919 }
4920
4921 gen_op_clear_ieee_excp_and_FTT();
4922 src1 = gen_load_fpr_F(dc, a->rs1);
4923 src2 = gen_load_fpr_F(dc, a->rs2);
4924 func(src1, tcg_env, src1, src2);
4925 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4926 gen_store_fpr_F(dc, a->rd, src1);
4927 return advance_pc(dc);
4928}
4929
4930TRANS(FADDs, ALL, do_env_fff, a, gen_helper_fadds)
4931TRANS(FSUBs, ALL, do_env_fff, a, gen_helper_fsubs)
4932TRANS(FMULs, ALL, do_env_fff, a, gen_helper_fmuls)
4933TRANS(FDIVs, ALL, do_env_fff, a, gen_helper_fdivs)
4934
e06c9f83
RH
4935static bool do_ddd(DisasContext *dc, arg_r_r_r *a,
4936 void (*func)(TCGv_i64, TCGv_i64, TCGv_i64))
4937{
4938 TCGv_i64 dst, src1, src2;
4939
4940 if (gen_trap_ifnofpu(dc)) {
4941 return true;
4942 }
4943
4944 dst = gen_dest_fpr_D(dc, a->rd);
4945 src1 = gen_load_fpr_D(dc, a->rs1);
4946 src2 = gen_load_fpr_D(dc, a->rs2);
4947 func(dst, src1, src2);
4948 gen_store_fpr_D(dc, a->rd, dst);
4949 return advance_pc(dc);
4950}
4951
4952TRANS(FMUL8x16, VIS1, do_ddd, a, gen_helper_fmul8x16)
4953TRANS(FMUL8x16AU, VIS1, do_ddd, a, gen_helper_fmul8x16au)
4954TRANS(FMUL8x16AL, VIS1, do_ddd, a, gen_helper_fmul8x16al)
4955TRANS(FMUL8SUx16, VIS1, do_ddd, a, gen_helper_fmul8sux16)
4956TRANS(FMUL8ULx16, VIS1, do_ddd, a, gen_helper_fmul8ulx16)
4957TRANS(FMULD8SUx16, VIS1, do_ddd, a, gen_helper_fmuld8sux16)
4958TRANS(FMULD8ULx16, VIS1, do_ddd, a, gen_helper_fmuld8ulx16)
4959TRANS(FPMERGE, VIS1, do_ddd, a, gen_helper_fpmerge)
4960TRANS(FEXPAND, VIS1, do_ddd, a, gen_helper_fexpand)
4961
4962TRANS(FPADD16, VIS1, do_ddd, a, tcg_gen_vec_add16_i64)
4963TRANS(FPADD32, VIS1, do_ddd, a, tcg_gen_vec_add32_i64)
4964TRANS(FPSUB16, VIS1, do_ddd, a, tcg_gen_vec_sub16_i64)
4965TRANS(FPSUB32, VIS1, do_ddd, a, tcg_gen_vec_sub32_i64)
4966TRANS(FNORd, VIS1, do_ddd, a, tcg_gen_nor_i64)
4967TRANS(FANDNOTd, VIS1, do_ddd, a, tcg_gen_andc_i64)
4968TRANS(FXORd, VIS1, do_ddd, a, tcg_gen_xor_i64)
4969TRANS(FNANDd, VIS1, do_ddd, a, tcg_gen_nand_i64)
4970TRANS(FANDd, VIS1, do_ddd, a, tcg_gen_and_i64)
4971TRANS(FXNORd, VIS1, do_ddd, a, tcg_gen_eqv_i64)
4972TRANS(FORNOTd, VIS1, do_ddd, a, tcg_gen_orc_i64)
4973TRANS(FORd, VIS1, do_ddd, a, tcg_gen_or_i64)
4974
4b6edc0a
RH
4975TRANS(FPACK32, VIS1, do_ddd, a, gen_op_fpack32)
4976TRANS(FALIGNDATAg, VIS1, do_ddd, a, gen_op_faligndata)
4977TRANS(BSHUFFLE, VIS2, do_ddd, a, gen_op_bshuffle)
4978
e2fa6bd1
RH
4979static bool do_rdd(DisasContext *dc, arg_r_r_r *a,
4980 void (*func)(TCGv, TCGv_i64, TCGv_i64))
4981{
4982 TCGv_i64 src1, src2;
4983 TCGv dst;
4984
4985 if (gen_trap_ifnofpu(dc)) {
4986 return true;
4987 }
4988
4989 dst = gen_dest_gpr(dc, a->rd);
4990 src1 = gen_load_fpr_D(dc, a->rs1);
4991 src2 = gen_load_fpr_D(dc, a->rs2);
4992 func(dst, src1, src2);
4993 gen_store_gpr(dc, a->rd, dst);
4994 return advance_pc(dc);
4995}
4996
4997TRANS(FPCMPLE16, VIS1, do_rdd, a, gen_helper_fcmple16)
4998TRANS(FPCMPNE16, VIS1, do_rdd, a, gen_helper_fcmpne16)
4999TRANS(FPCMPGT16, VIS1, do_rdd, a, gen_helper_fcmpgt16)
5000TRANS(FPCMPEQ16, VIS1, do_rdd, a, gen_helper_fcmpeq16)
5001
5002TRANS(FPCMPLE32, VIS1, do_rdd, a, gen_helper_fcmple32)
5003TRANS(FPCMPNE32, VIS1, do_rdd, a, gen_helper_fcmpne32)
5004TRANS(FPCMPGT32, VIS1, do_rdd, a, gen_helper_fcmpgt32)
5005TRANS(FPCMPEQ32, VIS1, do_rdd, a, gen_helper_fcmpeq32)
5006
f2a59b0a
RH
5007static bool do_env_ddd(DisasContext *dc, arg_r_r_r *a,
5008 void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
5009{
5010 TCGv_i64 dst, src1, src2;
5011
5012 if (gen_trap_ifnofpu(dc)) {
5013 return true;
5014 }
5015
5016 gen_op_clear_ieee_excp_and_FTT();
5017 dst = gen_dest_fpr_D(dc, a->rd);
5018 src1 = gen_load_fpr_D(dc, a->rs1);
5019 src2 = gen_load_fpr_D(dc, a->rs2);
5020 func(dst, tcg_env, src1, src2);
5021 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
5022 gen_store_fpr_D(dc, a->rd, dst);
5023 return advance_pc(dc);
5024}
5025
5026TRANS(FADDd, ALL, do_env_ddd, a, gen_helper_faddd)
5027TRANS(FSUBd, ALL, do_env_ddd, a, gen_helper_fsubd)
5028TRANS(FMULd, ALL, do_env_ddd, a, gen_helper_fmuld)
5029TRANS(FDIVd, ALL, do_env_ddd, a, gen_helper_fdivd)
5030
ff4c711b
RH
5031static bool trans_FsMULd(DisasContext *dc, arg_r_r_r *a)
5032{
5033 TCGv_i64 dst;
5034 TCGv_i32 src1, src2;
5035
5036 if (gen_trap_ifnofpu(dc)) {
5037 return true;
5038 }
5039 if (!(dc->def->features & CPU_FEATURE_FSMULD)) {
5040 return raise_unimpfpop(dc);
5041 }
5042
5043 gen_op_clear_ieee_excp_and_FTT();
5044 dst = gen_dest_fpr_D(dc, a->rd);
5045 src1 = gen_load_fpr_F(dc, a->rs1);
5046 src2 = gen_load_fpr_F(dc, a->rs2);
5047 gen_helper_fsmuld(dst, tcg_env, src1, src2);
5048 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
5049 gen_store_fpr_D(dc, a->rd, dst);
5050 return advance_pc(dc);
5051}
5052
afb04344
RH
5053static bool do_dddd(DisasContext *dc, arg_r_r_r *a,
5054 void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
5055{
5056 TCGv_i64 dst, src0, src1, src2;
5057
5058 if (gen_trap_ifnofpu(dc)) {
5059 return true;
5060 }
5061
5062 dst = gen_dest_fpr_D(dc, a->rd);
5063 src0 = gen_load_fpr_D(dc, a->rd);
5064 src1 = gen_load_fpr_D(dc, a->rs1);
5065 src2 = gen_load_fpr_D(dc, a->rs2);
5066 func(dst, src0, src1, src2);
5067 gen_store_fpr_D(dc, a->rd, dst);
5068 return advance_pc(dc);
5069}
5070
5071TRANS(PDIST, VIS1, do_dddd, a, gen_helper_pdist)
5072
a4056239
RH
5073static bool do_env_qqq(DisasContext *dc, arg_r_r_r *a,
5074 void (*func)(TCGv_env))
5075{
5076 if (gen_trap_ifnofpu(dc)) {
5077 return true;
5078 }
5079 if (gen_trap_float128(dc)) {
5080 return true;
5081 }
5082
5083 gen_op_clear_ieee_excp_and_FTT();
5084 gen_op_load_fpr_QT0(QFPREG(a->rs1));
5085 gen_op_load_fpr_QT1(QFPREG(a->rs2));
5086 func(tcg_env);
5087 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
5088 gen_op_store_QT0_fpr(QFPREG(a->rd));
5089 gen_update_fprs_dirty(dc, QFPREG(a->rd));
5090 return advance_pc(dc);
5091}
5092
5093TRANS(FADDq, ALL, do_env_qqq, a, gen_helper_faddq)
5094TRANS(FSUBq, ALL, do_env_qqq, a, gen_helper_fsubq)
5095TRANS(FMULq, ALL, do_env_qqq, a, gen_helper_fmulq)
5096TRANS(FDIVq, ALL, do_env_qqq, a, gen_helper_fdivq)
5097
5e3b17bb
RH
5098static bool trans_FdMULq(DisasContext *dc, arg_r_r_r *a)
5099{
5100 TCGv_i64 src1, src2;
5101
5102 if (gen_trap_ifnofpu(dc)) {
5103 return true;
5104 }
5105 if (gen_trap_float128(dc)) {
5106 return true;
5107 }
5108
5109 gen_op_clear_ieee_excp_and_FTT();
5110 src1 = gen_load_fpr_D(dc, a->rs1);
5111 src2 = gen_load_fpr_D(dc, a->rs2);
5112 gen_helper_fdmulq(tcg_env, src1, src2);
5113 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
5114 gen_op_store_QT0_fpr(QFPREG(a->rd));
5115 gen_update_fprs_dirty(dc, QFPREG(a->rd));
5116 return advance_pc(dc);
5117}
5118
f7ec8155
RH
5119static bool do_fmovr(DisasContext *dc, arg_FMOVRs *a, bool is_128,
5120 void (*func)(DisasContext *, DisasCompare *, int, int))
5121{
5122 DisasCompare cmp;
5123
5124 if (gen_trap_ifnofpu(dc)) {
5125 return true;
5126 }
5127 if (is_128 && gen_trap_float128(dc)) {
5128 return true;
5129 }
5130
5131 gen_op_clear_ieee_excp_and_FTT();
5132 gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
5133 func(dc, &cmp, a->rd, a->rs2);
5134 return advance_pc(dc);
5135}
5136
5137TRANS(FMOVRs, 64, do_fmovr, a, false, gen_fmovs)
5138TRANS(FMOVRd, 64, do_fmovr, a, false, gen_fmovd)
5139TRANS(FMOVRq, 64, do_fmovr, a, true, gen_fmovq)
5140
5141static bool do_fmovcc(DisasContext *dc, arg_FMOVscc *a, bool is_128,
5142 void (*func)(DisasContext *, DisasCompare *, int, int))
5143{
5144 DisasCompare cmp;
5145
5146 if (gen_trap_ifnofpu(dc)) {
5147 return true;
5148 }
5149 if (is_128 && gen_trap_float128(dc)) {
5150 return true;
5151 }
5152
5153 gen_op_clear_ieee_excp_and_FTT();
5154 gen_compare(&cmp, a->cc, a->cond, dc);
5155 func(dc, &cmp, a->rd, a->rs2);
5156 return advance_pc(dc);
5157}
5158
5159TRANS(FMOVscc, 64, do_fmovcc, a, false, gen_fmovs)
5160TRANS(FMOVdcc, 64, do_fmovcc, a, false, gen_fmovd)
5161TRANS(FMOVqcc, 64, do_fmovcc, a, true, gen_fmovq)
5162
5163static bool do_fmovfcc(DisasContext *dc, arg_FMOVsfcc *a, bool is_128,
5164 void (*func)(DisasContext *, DisasCompare *, int, int))
5165{
5166 DisasCompare cmp;
5167
5168 if (gen_trap_ifnofpu(dc)) {
5169 return true;
5170 }
5171 if (is_128 && gen_trap_float128(dc)) {
5172 return true;
5173 }
5174
5175 gen_op_clear_ieee_excp_and_FTT();
5176 gen_fcompare(&cmp, a->cc, a->cond);
5177 func(dc, &cmp, a->rd, a->rs2);
5178 return advance_pc(dc);
5179}
5180
5181TRANS(FMOVsfcc, 64, do_fmovfcc, a, false, gen_fmovs)
5182TRANS(FMOVdfcc, 64, do_fmovfcc, a, false, gen_fmovd)
5183TRANS(FMOVqfcc, 64, do_fmovfcc, a, true, gen_fmovq)
5184
40f9ad21
RH
5185static bool do_fcmps(DisasContext *dc, arg_FCMPs *a, bool e)
5186{
5187 TCGv_i32 src1, src2;
5188
5189 if (avail_32(dc) && a->cc != 0) {
5190 return false;
5191 }
5192 if (gen_trap_ifnofpu(dc)) {
5193 return true;
5194 }
5195
5196 gen_op_clear_ieee_excp_and_FTT();
5197 src1 = gen_load_fpr_F(dc, a->rs1);
5198 src2 = gen_load_fpr_F(dc, a->rs2);
5199 if (e) {
5200 gen_op_fcmpes(a->cc, src1, src2);
5201 } else {
5202 gen_op_fcmps(a->cc, src1, src2);
5203 }
5204 return advance_pc(dc);
5205}
5206
5207TRANS(FCMPs, ALL, do_fcmps, a, false)
5208TRANS(FCMPEs, ALL, do_fcmps, a, true)
5209
5210static bool do_fcmpd(DisasContext *dc, arg_FCMPd *a, bool e)
5211{
5212 TCGv_i64 src1, src2;
5213
5214 if (avail_32(dc) && a->cc != 0) {
5215 return false;
5216 }
5217 if (gen_trap_ifnofpu(dc)) {
5218 return true;
5219 }
5220
5221 gen_op_clear_ieee_excp_and_FTT();
5222 src1 = gen_load_fpr_D(dc, a->rs1);
5223 src2 = gen_load_fpr_D(dc, a->rs2);
5224 if (e) {
5225 gen_op_fcmped(a->cc, src1, src2);
5226 } else {
5227 gen_op_fcmpd(a->cc, src1, src2);
5228 }
5229 return advance_pc(dc);
5230}
5231
5232TRANS(FCMPd, ALL, do_fcmpd, a, false)
5233TRANS(FCMPEd, ALL, do_fcmpd, a, true)
5234
5235static bool do_fcmpq(DisasContext *dc, arg_FCMPq *a, bool e)
5236{
5237 if (avail_32(dc) && a->cc != 0) {
5238 return false;
5239 }
5240 if (gen_trap_ifnofpu(dc)) {
5241 return true;
5242 }
5243 if (gen_trap_float128(dc)) {
5244 return true;
5245 }
5246
5247 gen_op_clear_ieee_excp_and_FTT();
5248 gen_op_load_fpr_QT0(QFPREG(a->rs1));
5249 gen_op_load_fpr_QT1(QFPREG(a->rs2));
5250 if (e) {
5251 gen_op_fcmpeq(a->cc);
5252 } else {
5253 gen_op_fcmpq(a->cc);
5254 }
5255 return advance_pc(dc);
5256}
5257
5258TRANS(FCMPq, ALL, do_fcmpq, a, false)
5259TRANS(FCMPEq, ALL, do_fcmpq, a, true)
5260
6e61bc94 5261static void sparc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
7a3f1944 5262{
6e61bc94 5263 DisasContext *dc = container_of(dcbase, DisasContext, base);
b77af26e 5264 CPUSPARCState *env = cpu_env(cs);
6e61bc94 5265 int bound;
af00be49
EC
5266
5267 dc->pc = dc->base.pc_first;
6e61bc94 5268 dc->npc = (target_ulong)dc->base.tb->cs_base;
8393617c 5269 dc->cc_op = CC_OP_DYNAMIC;
6e61bc94 5270 dc->mem_idx = dc->base.tb->flags & TB_FLAG_MMU_MASK;
576e1c4c 5271 dc->def = &env->def;
6e61bc94
EC
5272 dc->fpu_enabled = tb_fpu_enabled(dc->base.tb->flags);
5273 dc->address_mask_32bit = tb_am_enabled(dc->base.tb->flags);
c9b459aa 5274#ifndef CONFIG_USER_ONLY
6e61bc94 5275 dc->supervisor = (dc->base.tb->flags & TB_FLAG_SUPER) != 0;
c9b459aa 5276#endif
a6d567e5 5277#ifdef TARGET_SPARC64
f9c816c0 5278 dc->fprs_dirty = 0;
6e61bc94 5279 dc->asi = (dc->base.tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff;
c9b459aa 5280#ifndef CONFIG_USER_ONLY
6e61bc94 5281 dc->hypervisor = (dc->base.tb->flags & TB_FLAG_HYPER) != 0;
c9b459aa 5282#endif
a6d567e5 5283#endif
6e61bc94
EC
5284 /*
5285 * if we reach a page boundary, we stop generation so that the
5286 * PC of a TT_TFAULT exception is always in the right page
5287 */
5288 bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
5289 dc->base.max_insns = MIN(dc->base.max_insns, bound);
5290}
cf495bcf 5291
6e61bc94
EC
5292static void sparc_tr_tb_start(DisasContextBase *db, CPUState *cs)
5293{
5294}
190ce7fb 5295
6e61bc94
EC
5296static void sparc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
5297{
5298 DisasContext *dc = container_of(dcbase, DisasContext, base);
633c4283 5299 target_ulong npc = dc->npc;
667b8e29 5300
633c4283
RH
5301 if (npc & 3) {
5302 switch (npc) {
5303 case JUMP_PC:
5304 assert(dc->jump_pc[1] == dc->pc + 4);
5305 npc = dc->jump_pc[0] | JUMP_PC;
5306 break;
5307 case DYNAMIC_PC:
5308 case DYNAMIC_PC_LOOKUP:
5309 npc = DYNAMIC_PC;
5310 break;
5311 default:
5312 g_assert_not_reached();
5313 }
6e61bc94 5314 }
633c4283 5315 tcg_gen_insn_start(dc->pc, npc);
6e61bc94 5316}
b933066a 5317
6e61bc94
EC
5318static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
5319{
5320 DisasContext *dc = container_of(dcbase, DisasContext, base);
b77af26e 5321 CPUSPARCState *env = cpu_env(cs);
6e61bc94 5322 unsigned int insn;
0f8a249a 5323
4e116893 5324 insn = translator_ldl(env, &dc->base, dc->pc);
6e61bc94 5325 dc->base.pc_next += 4;
878cc677
RH
5326
5327 if (!decode(dc, insn)) {
ba9c09b4 5328 gen_exception(dc, TT_ILL_INSN);
878cc677 5329 }
e80cfcfc 5330
6e61bc94
EC
5331 if (dc->base.is_jmp == DISAS_NORETURN) {
5332 return;
5333 }
5334 if (dc->pc != dc->base.pc_next) {
5335 dc->base.is_jmp = DISAS_TOO_MANY;
b09b2fd3 5336 }
6e61bc94
EC
5337}
5338
5339static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
5340{
5341 DisasContext *dc = container_of(dcbase, DisasContext, base);
186e7890 5342 DisasDelayException *e, *e_next;
633c4283 5343 bool may_lookup;
6e61bc94 5344
46bb0137
MCA
5345 switch (dc->base.is_jmp) {
5346 case DISAS_NEXT:
5347 case DISAS_TOO_MANY:
633c4283 5348 if (((dc->pc | dc->npc) & 3) == 0) {
72cbca10 5349 /* static PC and NPC: we can use direct chaining */
2f5680ee 5350 gen_goto_tb(dc, 0, dc->pc, dc->npc);
633c4283
RH
5351 break;
5352 }
5353
930f1865 5354 may_lookup = true;
633c4283
RH
5355 if (dc->pc & 3) {
5356 switch (dc->pc) {
5357 case DYNAMIC_PC_LOOKUP:
633c4283
RH
5358 break;
5359 case DYNAMIC_PC:
5360 may_lookup = false;
5361 break;
5362 default:
5363 g_assert_not_reached();
b09b2fd3 5364 }
633c4283
RH
5365 } else {
5366 tcg_gen_movi_tl(cpu_pc, dc->pc);
633c4283
RH
5367 }
5368
930f1865
RH
5369 if (dc->npc & 3) {
5370 switch (dc->npc) {
5371 case JUMP_PC:
5372 gen_generic_branch(dc);
5373 break;
5374 case DYNAMIC_PC:
5375 may_lookup = false;
5376 break;
5377 case DYNAMIC_PC_LOOKUP:
5378 break;
5379 default:
5380 g_assert_not_reached();
5381 }
5382 } else {
5383 tcg_gen_movi_tl(cpu_npc, dc->npc);
5384 }
633c4283
RH
5385 if (may_lookup) {
5386 tcg_gen_lookup_and_goto_ptr();
5387 } else {
07ea28b4 5388 tcg_gen_exit_tb(NULL, 0);
72cbca10 5389 }
46bb0137
MCA
5390 break;
5391
5392 case DISAS_NORETURN:
5393 break;
5394
5395 case DISAS_EXIT:
5396 /* Exit TB */
5397 save_state(dc);
5398 tcg_gen_exit_tb(NULL, 0);
5399 break;
5400
5401 default:
5402 g_assert_not_reached();
72cbca10 5403 }
186e7890
RH
5404
5405 for (e = dc->delay_excp_list; e ; e = e_next) {
5406 gen_set_label(e->lab);
5407
5408 tcg_gen_movi_tl(cpu_pc, e->pc);
5409 if (e->npc % 4 == 0) {
5410 tcg_gen_movi_tl(cpu_npc, e->npc);
5411 }
5412 gen_helper_raise_exception(tcg_env, e->excp);
5413
5414 e_next = e->next;
5415 g_free(e);
5416 }
6e61bc94
EC
5417}
5418
8eb806a7
RH
5419static void sparc_tr_disas_log(const DisasContextBase *dcbase,
5420 CPUState *cpu, FILE *logfile)
6e61bc94 5421{
8eb806a7
RH
5422 fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
5423 target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
6e61bc94
EC
5424}
5425
5426static const TranslatorOps sparc_tr_ops = {
5427 .init_disas_context = sparc_tr_init_disas_context,
5428 .tb_start = sparc_tr_tb_start,
5429 .insn_start = sparc_tr_insn_start,
6e61bc94
EC
5430 .translate_insn = sparc_tr_translate_insn,
5431 .tb_stop = sparc_tr_tb_stop,
5432 .disas_log = sparc_tr_disas_log,
5433};
5434
597f9b2d 5435void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
306c8721 5436 target_ulong pc, void *host_pc)
6e61bc94
EC
5437{
5438 DisasContext dc = {};
5439
306c8721 5440 translator_loop(cs, tb, max_insns, pc, host_pc, &sparc_tr_ops, &dc.base);
7a3f1944
FB
5441}
5442
55c3ceef 5443void sparc_tcg_init(void)
e80cfcfc 5444{
d2dc4069 5445 static const char gregnames[32][4] = {
0ea63844 5446 "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
d2dc4069
RH
5447 "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7",
5448 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
5449 "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7",
f5069b26 5450 };
0ea63844 5451 static const char fregnames[32][4] = {
30038fd8
RH
5452 "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14",
5453 "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30",
5454 "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",
5455 "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
714547bb 5456 };
aaed909a 5457
0ea63844 5458 static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
1a2fb1c0 5459#ifdef TARGET_SPARC64
0ea63844 5460 { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" },
0ea63844
RH
5461#endif
5462 { &cpu_cc_op, offsetof(CPUSPARCState, cc_op), "cc_op" },
0ea63844
RH
5463 };
5464
5465 static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
5466#ifdef TARGET_SPARC64
5467 { &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" },
2a1905c7
RH
5468 { &cpu_xcc_Z, offsetof(CPUSPARCState, xcc_Z), "xcc_Z" },
5469 { &cpu_xcc_C, offsetof(CPUSPARCState, xcc_C), "xcc_C" },
1a2fb1c0 5470#endif
2a1905c7
RH
5471 { &cpu_cc_N, offsetof(CPUSPARCState, cc_N), "cc_N" },
5472 { &cpu_cc_V, offsetof(CPUSPARCState, cc_V), "cc_V" },
5473 { &cpu_icc_Z, offsetof(CPUSPARCState, icc_Z), "icc_Z" },
5474 { &cpu_icc_C, offsetof(CPUSPARCState, icc_C), "icc_C" },
0ea63844
RH
5475 { &cpu_cond, offsetof(CPUSPARCState, cond), "cond" },
5476 { &cpu_cc_src, offsetof(CPUSPARCState, cc_src), "cc_src" },
5477 { &cpu_cc_src2, offsetof(CPUSPARCState, cc_src2), "cc_src2" },
5478 { &cpu_cc_dst, offsetof(CPUSPARCState, cc_dst), "cc_dst" },
5479 { &cpu_fsr, offsetof(CPUSPARCState, fsr), "fsr" },
5480 { &cpu_pc, offsetof(CPUSPARCState, pc), "pc" },
5481 { &cpu_npc, offsetof(CPUSPARCState, npc), "npc" },
5482 { &cpu_y, offsetof(CPUSPARCState, y), "y" },
0ea63844 5483 { &cpu_tbr, offsetof(CPUSPARCState, tbr), "tbr" },
0ea63844
RH
5484 };
5485
5486 unsigned int i;
5487
ad75a51e 5488 cpu_regwptr = tcg_global_mem_new_ptr(tcg_env,
0ea63844
RH
5489 offsetof(CPUSPARCState, regwptr),
5490 "regwptr");
5491
5492 for (i = 0; i < ARRAY_SIZE(r32); ++i) {
ad75a51e 5493 *r32[i].ptr = tcg_global_mem_new_i32(tcg_env, r32[i].off, r32[i].name);
0ea63844
RH
5494 }
5495
5496 for (i = 0; i < ARRAY_SIZE(rtl); ++i) {
ad75a51e 5497 *rtl[i].ptr = tcg_global_mem_new(tcg_env, rtl[i].off, rtl[i].name);
0ea63844
RH
5498 }
5499
f764718d 5500 cpu_regs[0] = NULL;
0ea63844 5501 for (i = 1; i < 8; ++i) {
ad75a51e 5502 cpu_regs[i] = tcg_global_mem_new(tcg_env,
d2dc4069
RH
5503 offsetof(CPUSPARCState, gregs[i]),
5504 gregnames[i]);
5505 }
5506
5507 for (i = 8; i < 32; ++i) {
5508 cpu_regs[i] = tcg_global_mem_new(cpu_regwptr,
5509 (i - 8) * sizeof(target_ulong),
5510 gregnames[i]);
0ea63844
RH
5511 }
5512
5513 for (i = 0; i < TARGET_DPREGS; i++) {
ad75a51e 5514 cpu_fpr[i] = tcg_global_mem_new_i64(tcg_env,
0ea63844
RH
5515 offsetof(CPUSPARCState, fpr[i]),
5516 fregnames[i]);
1a2fb1c0 5517 }
658138bc 5518}
d2856f1a 5519
f36aaa53
RH
5520void sparc_restore_state_to_opc(CPUState *cs,
5521 const TranslationBlock *tb,
5522 const uint64_t *data)
d2856f1a 5523{
f36aaa53
RH
5524 SPARCCPU *cpu = SPARC_CPU(cs);
5525 CPUSPARCState *env = &cpu->env;
bad729e2
RH
5526 target_ulong pc = data[0];
5527 target_ulong npc = data[1];
5528
5529 env->pc = pc;
6c42444f 5530 if (npc == DYNAMIC_PC) {
d2856f1a 5531 /* dynamic NPC: already stored */
6c42444f 5532 } else if (npc & JUMP_PC) {
d7da2a10
BS
5533 /* jump PC: use 'cond' and the jump targets of the translation */
5534 if (env->cond) {
6c42444f 5535 env->npc = npc & ~3;
d7da2a10 5536 } else {
6c42444f 5537 env->npc = pc + 4;
d7da2a10 5538 }
d2856f1a
AJ
5539 } else {
5540 env->npc = npc;
5541 }
5542}