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