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