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