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