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