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