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