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