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