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