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