]> git.ipfire.org Git - thirdparty/qemu.git/blame - target/sparc/translate.c
target/sparc: Implement UDIVX and SDIVX inline
[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_udiv(TCGv dst, TCGv src1, TCGv src2)
581{
13260103 582#ifdef TARGET_SPARC64
c2636853 583 gen_helper_udiv(dst, tcg_env, src1, src2);
13260103
RH
584 tcg_gen_ext32u_tl(dst, dst);
585#else
586 TCGv_i64 t64 = tcg_temp_new_i64();
587 gen_helper_udiv(t64, tcg_env, src1, src2);
588 tcg_gen_trunc_i64_tl(dst, t64);
589#endif
c2636853
RH
590}
591
592static void gen_op_sdiv(TCGv dst, TCGv src1, TCGv src2)
593{
13260103 594#ifdef TARGET_SPARC64
c2636853 595 gen_helper_sdiv(dst, tcg_env, src1, src2);
13260103
RH
596 tcg_gen_ext32s_tl(dst, dst);
597#else
598 TCGv_i64 t64 = tcg_temp_new_i64();
599 gen_helper_sdiv(t64, tcg_env, src1, src2);
600 tcg_gen_trunc_i64_tl(dst, t64);
601#endif
c2636853
RH
602}
603
604static void gen_op_udivcc(TCGv dst, TCGv src1, TCGv src2)
605{
13260103
RH
606 TCGv_i64 t64;
607
608#ifdef TARGET_SPARC64
609 t64 = cpu_cc_V;
610#else
611 t64 = tcg_temp_new_i64();
612#endif
613
614 gen_helper_udiv(t64, tcg_env, src1, src2);
615
616#ifdef TARGET_SPARC64
617 tcg_gen_ext32u_tl(cpu_cc_N, t64);
618 tcg_gen_shri_tl(cpu_cc_V, t64, 32);
619 tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
620 tcg_gen_movi_tl(cpu_icc_C, 0);
621#else
622 tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64);
623#endif
624 tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
625 tcg_gen_movi_tl(cpu_cc_C, 0);
626 tcg_gen_mov_tl(dst, cpu_cc_N);
c2636853
RH
627}
628
629static void gen_op_sdivcc(TCGv dst, TCGv src1, TCGv src2)
630{
13260103
RH
631 TCGv_i64 t64;
632
633#ifdef TARGET_SPARC64
634 t64 = cpu_cc_V;
635#else
636 t64 = tcg_temp_new_i64();
637#endif
638
639 gen_helper_sdiv(t64, tcg_env, src1, src2);
640
641#ifdef TARGET_SPARC64
642 tcg_gen_ext32s_tl(cpu_cc_N, t64);
643 tcg_gen_shri_tl(cpu_cc_V, t64, 32);
644 tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
645 tcg_gen_movi_tl(cpu_icc_C, 0);
646#else
647 tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64);
648#endif
649 tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
650 tcg_gen_movi_tl(cpu_cc_C, 0);
651 tcg_gen_mov_tl(dst, cpu_cc_N);
c2636853
RH
652}
653
a9aba13d
RH
654static void gen_op_taddcctv(TCGv dst, TCGv src1, TCGv src2)
655{
656 gen_helper_taddcctv(dst, tcg_env, src1, src2);
657}
658
659static void gen_op_tsubcctv(TCGv dst, TCGv src1, TCGv src2)
660{
661 gen_helper_tsubcctv(dst, tcg_env, src1, src2);
662}
663
9c6ec5bc
RH
664static void gen_op_popc(TCGv dst, TCGv src1, TCGv src2)
665{
666 tcg_gen_ctpop_tl(dst, src2);
667}
668
45bfed3b
RH
669#ifndef TARGET_SPARC64
670static void gen_helper_array8(TCGv dst, TCGv src1, TCGv src2)
671{
672 g_assert_not_reached();
673}
674#endif
675
676static void gen_op_array16(TCGv dst, TCGv src1, TCGv src2)
677{
678 gen_helper_array8(dst, src1, src2);
679 tcg_gen_shli_tl(dst, dst, 1);
680}
681
682static void gen_op_array32(TCGv dst, TCGv src1, TCGv src2)
683{
684 gen_helper_array8(dst, src1, src2);
685 tcg_gen_shli_tl(dst, dst, 2);
686}
687
2f722641
RH
688static void gen_op_fpack16(TCGv_i32 dst, TCGv_i64 src)
689{
690#ifdef TARGET_SPARC64
691 gen_helper_fpack16(dst, cpu_gsr, src);
692#else
693 g_assert_not_reached();
694#endif
695}
696
697static void gen_op_fpackfix(TCGv_i32 dst, TCGv_i64 src)
698{
699#ifdef TARGET_SPARC64
700 gen_helper_fpackfix(dst, cpu_gsr, src);
701#else
702 g_assert_not_reached();
703#endif
704}
705
4b6edc0a
RH
706static void gen_op_fpack32(TCGv_i64 dst, TCGv_i64 src1, TCGv_i64 src2)
707{
708#ifdef TARGET_SPARC64
709 gen_helper_fpack32(dst, cpu_gsr, src1, src2);
710#else
711 g_assert_not_reached();
712#endif
713}
714
715static void gen_op_faligndata(TCGv_i64 dst, TCGv_i64 s1, TCGv_i64 s2)
716{
717#ifdef TARGET_SPARC64
718 TCGv t1, t2, shift;
719
720 t1 = tcg_temp_new();
721 t2 = tcg_temp_new();
722 shift = tcg_temp_new();
723
724 tcg_gen_andi_tl(shift, cpu_gsr, 7);
725 tcg_gen_shli_tl(shift, shift, 3);
726 tcg_gen_shl_tl(t1, s1, shift);
727
728 /*
729 * A shift of 64 does not produce 0 in TCG. Divide this into a
730 * shift of (up to 63) followed by a constant shift of 1.
731 */
732 tcg_gen_xori_tl(shift, shift, 63);
733 tcg_gen_shr_tl(t2, s2, shift);
734 tcg_gen_shri_tl(t2, t2, 1);
735
736 tcg_gen_or_tl(dst, t1, t2);
737#else
738 g_assert_not_reached();
739#endif
740}
741
742static void gen_op_bshuffle(TCGv_i64 dst, TCGv_i64 src1, TCGv_i64 src2)
743{
744#ifdef TARGET_SPARC64
745 gen_helper_bshuffle(dst, cpu_gsr, src1, src2);
746#else
747 g_assert_not_reached();
748#endif
749}
750
19f329ad 751// 1
0c2e96c1 752static void gen_op_eval_ba(TCGv dst)
19f329ad
BS
753{
754 tcg_gen_movi_tl(dst, 1);
755}
756
19f329ad 757// 0
0c2e96c1 758static void gen_op_eval_bn(TCGv dst)
19f329ad
BS
759{
760 tcg_gen_movi_tl(dst, 0);
761}
762
19f329ad
BS
763/*
764 FPSR bit field FCC1 | FCC0:
765 0 =
766 1 <
767 2 >
768 3 unordered
769*/
0c2e96c1 770static void gen_mov_reg_FCC0(TCGv reg, TCGv src,
19f329ad
BS
771 unsigned int fcc_offset)
772{
ba6a9d8c 773 tcg_gen_shri_tl(reg, src, FSR_FCC0_SHIFT + fcc_offset);
19f329ad
BS
774 tcg_gen_andi_tl(reg, reg, 0x1);
775}
776
0c2e96c1 777static void gen_mov_reg_FCC1(TCGv reg, TCGv src, unsigned int fcc_offset)
19f329ad 778{
ba6a9d8c 779 tcg_gen_shri_tl(reg, src, FSR_FCC1_SHIFT + fcc_offset);
19f329ad
BS
780 tcg_gen_andi_tl(reg, reg, 0x1);
781}
782
783// !0: FCC0 | FCC1
0c2e96c1 784static void gen_op_eval_fbne(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 785{
de9e9d9f 786 TCGv t0 = tcg_temp_new();
19f329ad 787 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
788 gen_mov_reg_FCC1(t0, src, fcc_offset);
789 tcg_gen_or_tl(dst, dst, t0);
19f329ad
BS
790}
791
792// 1 or 2: FCC0 ^ FCC1
0c2e96c1 793static void gen_op_eval_fblg(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 794{
de9e9d9f 795 TCGv t0 = tcg_temp_new();
19f329ad 796 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
797 gen_mov_reg_FCC1(t0, src, fcc_offset);
798 tcg_gen_xor_tl(dst, dst, t0);
19f329ad
BS
799}
800
801// 1 or 3: FCC0
0c2e96c1 802static void gen_op_eval_fbul(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad
BS
803{
804 gen_mov_reg_FCC0(dst, src, fcc_offset);
805}
806
807// 1: FCC0 & !FCC1
0c2e96c1 808static void gen_op_eval_fbl(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 809{
de9e9d9f 810 TCGv t0 = tcg_temp_new();
19f329ad 811 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
812 gen_mov_reg_FCC1(t0, src, fcc_offset);
813 tcg_gen_andc_tl(dst, dst, t0);
19f329ad
BS
814}
815
816// 2 or 3: FCC1
0c2e96c1 817static void gen_op_eval_fbug(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad
BS
818{
819 gen_mov_reg_FCC1(dst, src, fcc_offset);
820}
821
822// 2: !FCC0 & FCC1
0c2e96c1 823static void gen_op_eval_fbg(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 824{
de9e9d9f 825 TCGv t0 = tcg_temp_new();
19f329ad 826 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
827 gen_mov_reg_FCC1(t0, src, fcc_offset);
828 tcg_gen_andc_tl(dst, t0, dst);
19f329ad
BS
829}
830
831// 3: FCC0 & FCC1
0c2e96c1 832static void gen_op_eval_fbu(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 833{
de9e9d9f 834 TCGv t0 = tcg_temp_new();
19f329ad 835 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
836 gen_mov_reg_FCC1(t0, src, fcc_offset);
837 tcg_gen_and_tl(dst, dst, t0);
19f329ad
BS
838}
839
840// 0: !(FCC0 | FCC1)
0c2e96c1 841static void gen_op_eval_fbe(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 842{
de9e9d9f 843 TCGv t0 = tcg_temp_new();
19f329ad 844 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
845 gen_mov_reg_FCC1(t0, src, fcc_offset);
846 tcg_gen_or_tl(dst, dst, t0);
19f329ad
BS
847 tcg_gen_xori_tl(dst, dst, 0x1);
848}
849
850// 0 or 3: !(FCC0 ^ FCC1)
0c2e96c1 851static void gen_op_eval_fbue(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 852{
de9e9d9f 853 TCGv t0 = tcg_temp_new();
19f329ad 854 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
855 gen_mov_reg_FCC1(t0, src, fcc_offset);
856 tcg_gen_xor_tl(dst, dst, t0);
19f329ad
BS
857 tcg_gen_xori_tl(dst, dst, 0x1);
858}
859
860// 0 or 2: !FCC0
0c2e96c1 861static void gen_op_eval_fbge(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad
BS
862{
863 gen_mov_reg_FCC0(dst, src, fcc_offset);
864 tcg_gen_xori_tl(dst, dst, 0x1);
865}
866
867// !1: !(FCC0 & !FCC1)
0c2e96c1 868static void gen_op_eval_fbuge(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 869{
de9e9d9f 870 TCGv t0 = tcg_temp_new();
19f329ad 871 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
872 gen_mov_reg_FCC1(t0, src, fcc_offset);
873 tcg_gen_andc_tl(dst, dst, t0);
19f329ad
BS
874 tcg_gen_xori_tl(dst, dst, 0x1);
875}
876
877// 0 or 1: !FCC1
0c2e96c1 878static void gen_op_eval_fble(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad
BS
879{
880 gen_mov_reg_FCC1(dst, src, fcc_offset);
881 tcg_gen_xori_tl(dst, dst, 0x1);
882}
883
884// !2: !(!FCC0 & FCC1)
0c2e96c1 885static void gen_op_eval_fbule(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 886{
de9e9d9f 887 TCGv t0 = tcg_temp_new();
19f329ad 888 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
889 gen_mov_reg_FCC1(t0, src, fcc_offset);
890 tcg_gen_andc_tl(dst, t0, dst);
19f329ad 891 tcg_gen_xori_tl(dst, dst, 0x1);
19f329ad
BS
892}
893
894// !3: !(FCC0 & FCC1)
0c2e96c1 895static void gen_op_eval_fbo(TCGv dst, TCGv src, unsigned int fcc_offset)
19f329ad 896{
de9e9d9f 897 TCGv t0 = tcg_temp_new();
19f329ad 898 gen_mov_reg_FCC0(dst, src, fcc_offset);
de9e9d9f
RH
899 gen_mov_reg_FCC1(t0, src, fcc_offset);
900 tcg_gen_and_tl(dst, dst, t0);
19f329ad
BS
901 tcg_gen_xori_tl(dst, dst, 0x1);
902}
903
89527e3a
RH
904static void finishing_insn(DisasContext *dc)
905{
906 /*
907 * From here, there is no future path through an unwinding exception.
908 * If the current insn cannot raise an exception, the computation of
909 * cpu_cond may be able to be elided.
910 */
911 if (dc->cpu_cond_live) {
912 tcg_gen_discard_tl(cpu_cond);
913 dc->cpu_cond_live = false;
914 }
915}
916
0c2e96c1 917static void gen_generic_branch(DisasContext *dc)
83469015 918{
00ab7e61
RH
919 TCGv npc0 = tcg_constant_tl(dc->jump_pc[0]);
920 TCGv npc1 = tcg_constant_tl(dc->jump_pc[1]);
533f042f 921 TCGv c2 = tcg_constant_tl(dc->jump.c2);
19f329ad 922
533f042f 923 tcg_gen_movcond_tl(dc->jump.cond, cpu_npc, dc->jump.c1, c2, npc0, npc1);
83469015
FB
924}
925
4af984a7
BS
926/* call this function before using the condition register as it may
927 have been set for a jump */
0c2e96c1 928static void flush_cond(DisasContext *dc)
83469015
FB
929{
930 if (dc->npc == JUMP_PC) {
2e655fe7 931 gen_generic_branch(dc);
99c82c47 932 dc->npc = DYNAMIC_PC_LOOKUP;
83469015
FB
933 }
934}
935
0c2e96c1 936static void save_npc(DisasContext *dc)
72cbca10 937{
633c4283
RH
938 if (dc->npc & 3) {
939 switch (dc->npc) {
940 case JUMP_PC:
941 gen_generic_branch(dc);
99c82c47 942 dc->npc = DYNAMIC_PC_LOOKUP;
633c4283
RH
943 break;
944 case DYNAMIC_PC:
945 case DYNAMIC_PC_LOOKUP:
946 break;
947 default:
948 g_assert_not_reached();
949 }
950 } else {
2f5680ee 951 tcg_gen_movi_tl(cpu_npc, dc->npc);
72cbca10
FB
952 }
953}
954
0c2e96c1 955static void save_state(DisasContext *dc)
20132b96
RH
956{
957 tcg_gen_movi_tl(cpu_pc, dc->pc);
934da7ee 958 save_npc(dc);
72cbca10
FB
959}
960
4fbe0067
RH
961static void gen_exception(DisasContext *dc, int which)
962{
89527e3a 963 finishing_insn(dc);
4fbe0067 964 save_state(dc);
ad75a51e 965 gen_helper_raise_exception(tcg_env, tcg_constant_i32(which));
af00be49 966 dc->base.is_jmp = DISAS_NORETURN;
4fbe0067
RH
967}
968
186e7890 969static TCGLabel *delay_exceptionv(DisasContext *dc, TCGv_i32 excp)
35e94905 970{
186e7890
RH
971 DisasDelayException *e = g_new0(DisasDelayException, 1);
972
973 e->next = dc->delay_excp_list;
974 dc->delay_excp_list = e;
975
976 e->lab = gen_new_label();
977 e->excp = excp;
978 e->pc = dc->pc;
979 /* Caller must have used flush_cond before branch. */
980 assert(e->npc != JUMP_PC);
981 e->npc = dc->npc;
982
983 return e->lab;
984}
985
986static TCGLabel *delay_exception(DisasContext *dc, int excp)
987{
988 return delay_exceptionv(dc, tcg_constant_i32(excp));
989}
990
991static void gen_check_align(DisasContext *dc, TCGv addr, int mask)
992{
993 TCGv t = tcg_temp_new();
994 TCGLabel *lab;
995
996 tcg_gen_andi_tl(t, addr, mask);
997
998 flush_cond(dc);
999 lab = delay_exception(dc, TT_UNALIGNED);
1000 tcg_gen_brcondi_tl(TCG_COND_NE, t, 0, lab);
35e94905
RH
1001}
1002
0c2e96c1 1003static void gen_mov_pc_npc(DisasContext *dc)
0bee699e 1004{
89527e3a
RH
1005 finishing_insn(dc);
1006
633c4283
RH
1007 if (dc->npc & 3) {
1008 switch (dc->npc) {
1009 case JUMP_PC:
1010 gen_generic_branch(dc);
1011 tcg_gen_mov_tl(cpu_pc, cpu_npc);
99c82c47 1012 dc->pc = DYNAMIC_PC_LOOKUP;
633c4283
RH
1013 break;
1014 case DYNAMIC_PC:
1015 case DYNAMIC_PC_LOOKUP:
1016 tcg_gen_mov_tl(cpu_pc, cpu_npc);
1017 dc->pc = dc->npc;
1018 break;
1019 default:
1020 g_assert_not_reached();
1021 }
0bee699e
FB
1022 } else {
1023 dc->pc = dc->npc;
1024 }
1025}
1026
2a484ecf 1027static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
416fcaea 1028 DisasContext *dc)
19f329ad 1029{
b597eedc 1030 TCGv t1;
416fcaea 1031
2a1905c7 1032 cmp->c1 = t1 = tcg_temp_new();
c8507ebf 1033 cmp->c2 = 0;
2a1905c7
RH
1034
1035 switch (cond & 7) {
1036 case 0x0: /* never */
1037 cmp->cond = TCG_COND_NEVER;
c8507ebf 1038 cmp->c1 = tcg_constant_tl(0);
2a1905c7
RH
1039 break;
1040
1041 case 0x1: /* eq: Z */
1042 cmp->cond = TCG_COND_EQ;
1043 if (TARGET_LONG_BITS == 32 || xcc) {
1044 tcg_gen_mov_tl(t1, cpu_cc_Z);
1045 } else {
1046 tcg_gen_ext32u_tl(t1, cpu_icc_Z);
1047 }
1048 break;
1049
1050 case 0x2: /* le: Z | (N ^ V) */
1051 /*
1052 * Simplify:
1053 * cc_Z || (N ^ V) < 0 NE
1054 * cc_Z && !((N ^ V) < 0) EQ
1055 * cc_Z & ~((N ^ V) >> TLB) EQ
1056 */
1057 cmp->cond = TCG_COND_EQ;
1058 tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V);
1059 tcg_gen_sextract_tl(t1, t1, xcc ? 63 : 31, 1);
1060 tcg_gen_andc_tl(t1, xcc ? cpu_cc_Z : cpu_icc_Z, t1);
1061 if (TARGET_LONG_BITS == 64 && !xcc) {
1062 tcg_gen_ext32u_tl(t1, t1);
1063 }
1064 break;
1065
1066 case 0x3: /* lt: N ^ V */
1067 cmp->cond = TCG_COND_LT;
1068 tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V);
1069 if (TARGET_LONG_BITS == 64 && !xcc) {
1070 tcg_gen_ext32s_tl(t1, t1);
1071 }
1072 break;
1073
1074 case 0x4: /* leu: Z | C */
1075 /*
1076 * Simplify:
1077 * cc_Z == 0 || cc_C != 0 NE
1078 * cc_Z != 0 && cc_C == 0 EQ
1079 * cc_Z & (cc_C ? 0 : -1) EQ
1080 * cc_Z & (cc_C - 1) EQ
1081 */
1082 cmp->cond = TCG_COND_EQ;
1083 if (TARGET_LONG_BITS == 32 || xcc) {
1084 tcg_gen_subi_tl(t1, cpu_cc_C, 1);
1085 tcg_gen_and_tl(t1, t1, cpu_cc_Z);
1086 } else {
1087 tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1);
1088 tcg_gen_subi_tl(t1, t1, 1);
1089 tcg_gen_and_tl(t1, t1, cpu_icc_Z);
1090 tcg_gen_ext32u_tl(t1, t1);
1091 }
1092 break;
1093
1094 case 0x5: /* ltu: C */
2a484ecf 1095 cmp->cond = TCG_COND_NE;
2a1905c7
RH
1096 if (TARGET_LONG_BITS == 32 || xcc) {
1097 tcg_gen_mov_tl(t1, cpu_cc_C);
1098 } else {
1099 tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1);
1100 }
1101 break;
2a484ecf 1102
2a1905c7
RH
1103 case 0x6: /* neg: N */
1104 cmp->cond = TCG_COND_LT;
1105 if (TARGET_LONG_BITS == 32 || xcc) {
1106 tcg_gen_mov_tl(t1, cpu_cc_N);
1107 } else {
1108 tcg_gen_ext32s_tl(t1, cpu_cc_N);
2a484ecf 1109 }
19f329ad 1110 break;
2a1905c7
RH
1111
1112 case 0x7: /* vs: V */
1113 cmp->cond = TCG_COND_LT;
1114 if (TARGET_LONG_BITS == 32 || xcc) {
1115 tcg_gen_mov_tl(t1, cpu_cc_V);
1116 } else {
1117 tcg_gen_ext32s_tl(t1, cpu_cc_V);
1118 }
1119 break;
1120 }
1121 if (cond & 8) {
1122 cmp->cond = tcg_invert_cond(cmp->cond);
19f329ad
BS
1123 }
1124}
7a3f1944 1125
416fcaea 1126static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond)
e8af50a3 1127{
19f329ad 1128 unsigned int offset;
416fcaea
RH
1129 TCGv r_dst;
1130
1131 /* For now we still generate a straight boolean result. */
1132 cmp->cond = TCG_COND_NE;
416fcaea 1133 cmp->c1 = r_dst = tcg_temp_new();
c8507ebf 1134 cmp->c2 = 0;
19f329ad 1135
19f329ad
BS
1136 switch (cc) {
1137 default:
1138 case 0x0:
1139 offset = 0;
1140 break;
1141 case 0x1:
1142 offset = 32 - 10;
1143 break;
1144 case 0x2:
1145 offset = 34 - 10;
1146 break;
1147 case 0x3:
1148 offset = 36 - 10;
1149 break;
1150 }
1151
1152 switch (cond) {
1153 case 0x0:
1154 gen_op_eval_bn(r_dst);
1155 break;
1156 case 0x1:
87e92502 1157 gen_op_eval_fbne(r_dst, cpu_fsr, offset);
19f329ad
BS
1158 break;
1159 case 0x2:
87e92502 1160 gen_op_eval_fblg(r_dst, cpu_fsr, offset);
19f329ad
BS
1161 break;
1162 case 0x3:
87e92502 1163 gen_op_eval_fbul(r_dst, cpu_fsr, offset);
19f329ad
BS
1164 break;
1165 case 0x4:
87e92502 1166 gen_op_eval_fbl(r_dst, cpu_fsr, offset);
19f329ad
BS
1167 break;
1168 case 0x5:
87e92502 1169 gen_op_eval_fbug(r_dst, cpu_fsr, offset);
19f329ad
BS
1170 break;
1171 case 0x6:
87e92502 1172 gen_op_eval_fbg(r_dst, cpu_fsr, offset);
19f329ad
BS
1173 break;
1174 case 0x7:
87e92502 1175 gen_op_eval_fbu(r_dst, cpu_fsr, offset);
19f329ad
BS
1176 break;
1177 case 0x8:
1178 gen_op_eval_ba(r_dst);
1179 break;
1180 case 0x9:
87e92502 1181 gen_op_eval_fbe(r_dst, cpu_fsr, offset);
19f329ad
BS
1182 break;
1183 case 0xa:
87e92502 1184 gen_op_eval_fbue(r_dst, cpu_fsr, offset);
19f329ad
BS
1185 break;
1186 case 0xb:
87e92502 1187 gen_op_eval_fbge(r_dst, cpu_fsr, offset);
19f329ad
BS
1188 break;
1189 case 0xc:
87e92502 1190 gen_op_eval_fbuge(r_dst, cpu_fsr, offset);
19f329ad
BS
1191 break;
1192 case 0xd:
87e92502 1193 gen_op_eval_fble(r_dst, cpu_fsr, offset);
19f329ad
BS
1194 break;
1195 case 0xe:
87e92502 1196 gen_op_eval_fbule(r_dst, cpu_fsr, offset);
19f329ad
BS
1197 break;
1198 case 0xf:
87e92502 1199 gen_op_eval_fbo(r_dst, cpu_fsr, offset);
19f329ad
BS
1200 break;
1201 }
e8af50a3 1202}
00f219bf
BS
1203
1204// Inverted logic
ab9ffe98
RH
1205static const TCGCond gen_tcg_cond_reg[8] = {
1206 TCG_COND_NEVER, /* reserved */
00f219bf
BS
1207 TCG_COND_NE,
1208 TCG_COND_GT,
1209 TCG_COND_GE,
ab9ffe98 1210 TCG_COND_NEVER, /* reserved */
00f219bf
BS
1211 TCG_COND_EQ,
1212 TCG_COND_LE,
1213 TCG_COND_LT,
1214};
19f329ad 1215
416fcaea
RH
1216static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src)
1217{
1218 cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]);
816f89b7 1219 cmp->c1 = tcg_temp_new();
c8507ebf 1220 cmp->c2 = 0;
816f89b7 1221 tcg_gen_mov_tl(cmp->c1, r_src);
416fcaea
RH
1222}
1223
baf3dbf2
RH
1224static void gen_op_clear_ieee_excp_and_FTT(void)
1225{
1226 tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK);
1227}
1228
1229static void gen_op_fmovs(TCGv_i32 dst, TCGv_i32 src)
1230{
1231 gen_op_clear_ieee_excp_and_FTT();
1232 tcg_gen_mov_i32(dst, src);
1233}
1234
1235static void gen_op_fnegs(TCGv_i32 dst, TCGv_i32 src)
1236{
1237 gen_op_clear_ieee_excp_and_FTT();
1238 gen_helper_fnegs(dst, src);
1239}
1240
1241static void gen_op_fabss(TCGv_i32 dst, TCGv_i32 src)
1242{
1243 gen_op_clear_ieee_excp_and_FTT();
1244 gen_helper_fabss(dst, src);
1245}
1246
c6d83e4f
RH
1247static void gen_op_fmovd(TCGv_i64 dst, TCGv_i64 src)
1248{
1249 gen_op_clear_ieee_excp_and_FTT();
1250 tcg_gen_mov_i64(dst, src);
1251}
1252
1253static void gen_op_fnegd(TCGv_i64 dst, TCGv_i64 src)
1254{
1255 gen_op_clear_ieee_excp_and_FTT();
1256 gen_helper_fnegd(dst, src);
1257}
1258
1259static void gen_op_fabsd(TCGv_i64 dst, TCGv_i64 src)
1260{
1261 gen_op_clear_ieee_excp_and_FTT();
1262 gen_helper_fabsd(dst, src);
1263}
1264
3475187d 1265#ifdef TARGET_SPARC64
0c2e96c1 1266static void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
7e8c2b6c 1267{
714547bb
BS
1268 switch (fccno) {
1269 case 0:
ad75a51e 1270 gen_helper_fcmps(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1271 break;
1272 case 1:
ad75a51e 1273 gen_helper_fcmps_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1274 break;
1275 case 2:
ad75a51e 1276 gen_helper_fcmps_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1277 break;
1278 case 3:
ad75a51e 1279 gen_helper_fcmps_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1280 break;
1281 }
7e8c2b6c
BS
1282}
1283
0c2e96c1 1284static void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
7e8c2b6c 1285{
a7812ae4
PB
1286 switch (fccno) {
1287 case 0:
ad75a51e 1288 gen_helper_fcmpd(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1289 break;
1290 case 1:
ad75a51e 1291 gen_helper_fcmpd_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1292 break;
1293 case 2:
ad75a51e 1294 gen_helper_fcmpd_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1295 break;
1296 case 3:
ad75a51e 1297 gen_helper_fcmpd_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1298 break;
1299 }
7e8c2b6c
BS
1300}
1301
0c2e96c1 1302static void gen_op_fcmpq(int fccno)
7e8c2b6c 1303{
a7812ae4
PB
1304 switch (fccno) {
1305 case 0:
ad75a51e 1306 gen_helper_fcmpq(cpu_fsr, tcg_env);
a7812ae4
PB
1307 break;
1308 case 1:
ad75a51e 1309 gen_helper_fcmpq_fcc1(cpu_fsr, tcg_env);
a7812ae4
PB
1310 break;
1311 case 2:
ad75a51e 1312 gen_helper_fcmpq_fcc2(cpu_fsr, tcg_env);
a7812ae4
PB
1313 break;
1314 case 3:
ad75a51e 1315 gen_helper_fcmpq_fcc3(cpu_fsr, tcg_env);
a7812ae4
PB
1316 break;
1317 }
7e8c2b6c 1318}
7e8c2b6c 1319
0c2e96c1 1320static void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
7e8c2b6c 1321{
714547bb
BS
1322 switch (fccno) {
1323 case 0:
ad75a51e 1324 gen_helper_fcmpes(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1325 break;
1326 case 1:
ad75a51e 1327 gen_helper_fcmpes_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1328 break;
1329 case 2:
ad75a51e 1330 gen_helper_fcmpes_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1331 break;
1332 case 3:
ad75a51e 1333 gen_helper_fcmpes_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2);
714547bb
BS
1334 break;
1335 }
7e8c2b6c
BS
1336}
1337
0c2e96c1 1338static void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
7e8c2b6c 1339{
a7812ae4
PB
1340 switch (fccno) {
1341 case 0:
ad75a51e 1342 gen_helper_fcmped(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1343 break;
1344 case 1:
ad75a51e 1345 gen_helper_fcmped_fcc1(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1346 break;
1347 case 2:
ad75a51e 1348 gen_helper_fcmped_fcc2(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1349 break;
1350 case 3:
ad75a51e 1351 gen_helper_fcmped_fcc3(cpu_fsr, tcg_env, r_rs1, r_rs2);
a7812ae4
PB
1352 break;
1353 }
7e8c2b6c
BS
1354}
1355
0c2e96c1 1356static void gen_op_fcmpeq(int fccno)
7e8c2b6c 1357{
a7812ae4
PB
1358 switch (fccno) {
1359 case 0:
ad75a51e 1360 gen_helper_fcmpeq(cpu_fsr, tcg_env);
a7812ae4
PB
1361 break;
1362 case 1:
ad75a51e 1363 gen_helper_fcmpeq_fcc1(cpu_fsr, tcg_env);
a7812ae4
PB
1364 break;
1365 case 2:
ad75a51e 1366 gen_helper_fcmpeq_fcc2(cpu_fsr, tcg_env);
a7812ae4
PB
1367 break;
1368 case 3:
ad75a51e 1369 gen_helper_fcmpeq_fcc3(cpu_fsr, tcg_env);
a7812ae4
PB
1370 break;
1371 }
7e8c2b6c 1372}
7e8c2b6c
BS
1373
1374#else
1375
0c2e96c1 1376static void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
7e8c2b6c 1377{
ad75a51e 1378 gen_helper_fcmps(cpu_fsr, tcg_env, r_rs1, r_rs2);
7e8c2b6c
BS
1379}
1380
0c2e96c1 1381static void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
7e8c2b6c 1382{
ad75a51e 1383 gen_helper_fcmpd(cpu_fsr, tcg_env, r_rs1, r_rs2);
7e8c2b6c
BS
1384}
1385
0c2e96c1 1386static void gen_op_fcmpq(int fccno)
7e8c2b6c 1387{
ad75a51e 1388 gen_helper_fcmpq(cpu_fsr, tcg_env);
7e8c2b6c 1389}
7e8c2b6c 1390
0c2e96c1 1391static void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
7e8c2b6c 1392{
ad75a51e 1393 gen_helper_fcmpes(cpu_fsr, tcg_env, r_rs1, r_rs2);
7e8c2b6c
BS
1394}
1395
0c2e96c1 1396static void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
7e8c2b6c 1397{
ad75a51e 1398 gen_helper_fcmped(cpu_fsr, tcg_env, r_rs1, r_rs2);
7e8c2b6c
BS
1399}
1400
0c2e96c1 1401static void gen_op_fcmpeq(int fccno)
7e8c2b6c 1402{
ad75a51e 1403 gen_helper_fcmpeq(cpu_fsr, tcg_env);
7e8c2b6c
BS
1404}
1405#endif
1406
4fbe0067 1407static void gen_op_fpexception_im(DisasContext *dc, int fsr_flags)
134d77a1 1408{
47ad35f1 1409 tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
87e92502 1410 tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
4fbe0067 1411 gen_exception(dc, TT_FP_EXCP);
134d77a1
BS
1412}
1413
5b12f1e8 1414static int gen_trap_ifnofpu(DisasContext *dc)
a80dde08
FB
1415{
1416#if !defined(CONFIG_USER_ONLY)
1417 if (!dc->fpu_enabled) {
4fbe0067 1418 gen_exception(dc, TT_NFPU_INSN);
a80dde08
FB
1419 return 1;
1420 }
1421#endif
1422 return 0;
1423}
1424
1a2fb1c0 1425/* asi moves */
7ec1e5ea
RH
1426typedef enum {
1427 GET_ASI_HELPER,
1428 GET_ASI_EXCP,
f0913be0 1429 GET_ASI_DIRECT,
e4dc0052 1430 GET_ASI_DTWINX,
ca5ce572
RH
1431 GET_ASI_BLOCK,
1432 GET_ASI_SHORT,
34810610
RH
1433 GET_ASI_BCOPY,
1434 GET_ASI_BFILL,
7ec1e5ea
RH
1435} ASIType;
1436
1437typedef struct {
1438 ASIType type;
a6d567e5 1439 int asi;
f0913be0 1440 int mem_idx;
14776ab5 1441 MemOp memop;
7ec1e5ea 1442} DisasASI;
1a2fb1c0 1443
811cc0b0
RH
1444/*
1445 * Build DisasASI.
1446 * For asi == -1, treat as non-asi.
1447 * For ask == -2, treat as immediate offset (v8 error, v9 %asi).
1448 */
1449static DisasASI resolve_asi(DisasContext *dc, int asi, MemOp memop)
7ec1e5ea 1450{
7ec1e5ea 1451 ASIType type = GET_ASI_HELPER;
f0913be0 1452 int mem_idx = dc->mem_idx;
7ec1e5ea 1453
811cc0b0
RH
1454 if (asi == -1) {
1455 /* Artificial "non-asi" case. */
1456 type = GET_ASI_DIRECT;
1457 goto done;
1458 }
1459
7ec1e5ea
RH
1460#ifndef TARGET_SPARC64
1461 /* Before v9, all asis are immediate and privileged. */
811cc0b0 1462 if (asi < 0) {
22e70060 1463 gen_exception(dc, TT_ILL_INSN);
7ec1e5ea
RH
1464 type = GET_ASI_EXCP;
1465 } else if (supervisor(dc)
1466 /* Note that LEON accepts ASI_USERDATA in user mode, for
1467 use with CASA. Also note that previous versions of
0cc1f4bf
RH
1468 QEMU allowed (and old versions of gcc emitted) ASI_P
1469 for LEON, which is incorrect. */
1470 || (asi == ASI_USERDATA
7ec1e5ea 1471 && (dc->def->features & CPU_FEATURE_CASA))) {
f0913be0
RH
1472 switch (asi) {
1473 case ASI_USERDATA: /* User data access */
1474 mem_idx = MMU_USER_IDX;
1475 type = GET_ASI_DIRECT;
1476 break;
1477 case ASI_KERNELDATA: /* Supervisor data access */
1478 mem_idx = MMU_KERNEL_IDX;
1479 type = GET_ASI_DIRECT;
1480 break;
7f87c905
RH
1481 case ASI_M_BYPASS: /* MMU passthrough */
1482 case ASI_LEON_BYPASS: /* LEON MMU passthrough */
1483 mem_idx = MMU_PHYS_IDX;
1484 type = GET_ASI_DIRECT;
1485 break;
34810610
RH
1486 case ASI_M_BCOPY: /* Block copy, sta access */
1487 mem_idx = MMU_KERNEL_IDX;
1488 type = GET_ASI_BCOPY;
1489 break;
1490 case ASI_M_BFILL: /* Block fill, stda access */
1491 mem_idx = MMU_KERNEL_IDX;
1492 type = GET_ASI_BFILL;
1493 break;
f0913be0 1494 }
6e10f37c
KF
1495
1496 /* MMU_PHYS_IDX is used when the MMU is disabled to passthrough the
1497 * permissions check in get_physical_address(..).
1498 */
1499 mem_idx = (dc->mem_idx == MMU_PHYS_IDX) ? MMU_PHYS_IDX : mem_idx;
1a2fb1c0 1500 } else {
7ec1e5ea
RH
1501 gen_exception(dc, TT_PRIV_INSN);
1502 type = GET_ASI_EXCP;
1503 }
1504#else
811cc0b0 1505 if (asi < 0) {
7ec1e5ea 1506 asi = dc->asi;
1a2fb1c0 1507 }
f0913be0
RH
1508 /* With v9, all asis below 0x80 are privileged. */
1509 /* ??? We ought to check cpu_has_hypervisor, but we didn't copy
1510 down that bit into DisasContext. For the moment that's ok,
1511 since the direct implementations below doesn't have any ASIs
1512 in the restricted [0x30, 0x7f] range, and the check will be
1513 done properly in the helper. */
1514 if (!supervisor(dc) && asi < 0x80) {
1515 gen_exception(dc, TT_PRIV_ACT);
1516 type = GET_ASI_EXCP;
1517 } else {
1518 switch (asi) {
7f87c905
RH
1519 case ASI_REAL: /* Bypass */
1520 case ASI_REAL_IO: /* Bypass, non-cacheable */
1521 case ASI_REAL_L: /* Bypass LE */
1522 case ASI_REAL_IO_L: /* Bypass, non-cacheable LE */
1523 case ASI_TWINX_REAL: /* Real address, twinx */
1524 case ASI_TWINX_REAL_L: /* Real address, twinx, LE */
34a6e13d
RH
1525 case ASI_QUAD_LDD_PHYS:
1526 case ASI_QUAD_LDD_PHYS_L:
7f87c905
RH
1527 mem_idx = MMU_PHYS_IDX;
1528 break;
f0913be0
RH
1529 case ASI_N: /* Nucleus */
1530 case ASI_NL: /* Nucleus LE */
e4dc0052
RH
1531 case ASI_TWINX_N:
1532 case ASI_TWINX_NL:
34a6e13d
RH
1533 case ASI_NUCLEUS_QUAD_LDD:
1534 case ASI_NUCLEUS_QUAD_LDD_L:
9a10756d 1535 if (hypervisor(dc)) {
84f8f587 1536 mem_idx = MMU_PHYS_IDX;
9a10756d
AT
1537 } else {
1538 mem_idx = MMU_NUCLEUS_IDX;
1539 }
f0913be0
RH
1540 break;
1541 case ASI_AIUP: /* As if user primary */
1542 case ASI_AIUPL: /* As if user primary LE */
e4dc0052
RH
1543 case ASI_TWINX_AIUP:
1544 case ASI_TWINX_AIUP_L:
ca5ce572
RH
1545 case ASI_BLK_AIUP_4V:
1546 case ASI_BLK_AIUP_L_4V:
1547 case ASI_BLK_AIUP:
1548 case ASI_BLK_AIUPL:
f0913be0
RH
1549 mem_idx = MMU_USER_IDX;
1550 break;
1551 case ASI_AIUS: /* As if user secondary */
1552 case ASI_AIUSL: /* As if user secondary LE */
e4dc0052
RH
1553 case ASI_TWINX_AIUS:
1554 case ASI_TWINX_AIUS_L:
ca5ce572
RH
1555 case ASI_BLK_AIUS_4V:
1556 case ASI_BLK_AIUS_L_4V:
1557 case ASI_BLK_AIUS:
1558 case ASI_BLK_AIUSL:
f0913be0
RH
1559 mem_idx = MMU_USER_SECONDARY_IDX;
1560 break;
1561 case ASI_S: /* Secondary */
1562 case ASI_SL: /* Secondary LE */
e4dc0052
RH
1563 case ASI_TWINX_S:
1564 case ASI_TWINX_SL:
ca5ce572
RH
1565 case ASI_BLK_COMMIT_S:
1566 case ASI_BLK_S:
1567 case ASI_BLK_SL:
1568 case ASI_FL8_S:
1569 case ASI_FL8_SL:
1570 case ASI_FL16_S:
1571 case ASI_FL16_SL:
f0913be0
RH
1572 if (mem_idx == MMU_USER_IDX) {
1573 mem_idx = MMU_USER_SECONDARY_IDX;
1574 } else if (mem_idx == MMU_KERNEL_IDX) {
1575 mem_idx = MMU_KERNEL_SECONDARY_IDX;
1576 }
1577 break;
1578 case ASI_P: /* Primary */
1579 case ASI_PL: /* Primary LE */
e4dc0052
RH
1580 case ASI_TWINX_P:
1581 case ASI_TWINX_PL:
ca5ce572
RH
1582 case ASI_BLK_COMMIT_P:
1583 case ASI_BLK_P:
1584 case ASI_BLK_PL:
1585 case ASI_FL8_P:
1586 case ASI_FL8_PL:
1587 case ASI_FL16_P:
1588 case ASI_FL16_PL:
f0913be0
RH
1589 break;
1590 }
1591 switch (asi) {
7f87c905
RH
1592 case ASI_REAL:
1593 case ASI_REAL_IO:
1594 case ASI_REAL_L:
1595 case ASI_REAL_IO_L:
f0913be0
RH
1596 case ASI_N:
1597 case ASI_NL:
1598 case ASI_AIUP:
1599 case ASI_AIUPL:
1600 case ASI_AIUS:
1601 case ASI_AIUSL:
1602 case ASI_S:
1603 case ASI_SL:
1604 case ASI_P:
1605 case ASI_PL:
1606 type = GET_ASI_DIRECT;
1607 break;
7f87c905
RH
1608 case ASI_TWINX_REAL:
1609 case ASI_TWINX_REAL_L:
e4dc0052
RH
1610 case ASI_TWINX_N:
1611 case ASI_TWINX_NL:
1612 case ASI_TWINX_AIUP:
1613 case ASI_TWINX_AIUP_L:
1614 case ASI_TWINX_AIUS:
1615 case ASI_TWINX_AIUS_L:
1616 case ASI_TWINX_P:
1617 case ASI_TWINX_PL:
1618 case ASI_TWINX_S:
1619 case ASI_TWINX_SL:
34a6e13d
RH
1620 case ASI_QUAD_LDD_PHYS:
1621 case ASI_QUAD_LDD_PHYS_L:
1622 case ASI_NUCLEUS_QUAD_LDD:
1623 case ASI_NUCLEUS_QUAD_LDD_L:
e4dc0052
RH
1624 type = GET_ASI_DTWINX;
1625 break;
ca5ce572
RH
1626 case ASI_BLK_COMMIT_P:
1627 case ASI_BLK_COMMIT_S:
1628 case ASI_BLK_AIUP_4V:
1629 case ASI_BLK_AIUP_L_4V:
1630 case ASI_BLK_AIUP:
1631 case ASI_BLK_AIUPL:
1632 case ASI_BLK_AIUS_4V:
1633 case ASI_BLK_AIUS_L_4V:
1634 case ASI_BLK_AIUS:
1635 case ASI_BLK_AIUSL:
1636 case ASI_BLK_S:
1637 case ASI_BLK_SL:
1638 case ASI_BLK_P:
1639 case ASI_BLK_PL:
1640 type = GET_ASI_BLOCK;
1641 break;
1642 case ASI_FL8_S:
1643 case ASI_FL8_SL:
1644 case ASI_FL8_P:
1645 case ASI_FL8_PL:
1646 memop = MO_UB;
1647 type = GET_ASI_SHORT;
1648 break;
1649 case ASI_FL16_S:
1650 case ASI_FL16_SL:
1651 case ASI_FL16_P:
1652 case ASI_FL16_PL:
1653 memop = MO_TEUW;
1654 type = GET_ASI_SHORT;
1655 break;
f0913be0
RH
1656 }
1657 /* The little-endian asis all have bit 3 set. */
1658 if (asi & 8) {
1659 memop ^= MO_BSWAP;
1660 }
1661 }
7ec1e5ea
RH
1662#endif
1663
811cc0b0 1664 done:
f0913be0 1665 return (DisasASI){ type, asi, mem_idx, memop };
0425bee5
BS
1666}
1667
a76779ee
RH
1668#if defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
1669static void gen_helper_ld_asi(TCGv_i64 r, TCGv_env e, TCGv a,
1670 TCGv_i32 asi, TCGv_i32 mop)
1671{
1672 g_assert_not_reached();
1673}
1674
1675static void gen_helper_st_asi(TCGv_env e, TCGv a, TCGv_i64 r,
1676 TCGv_i32 asi, TCGv_i32 mop)
1677{
1678 g_assert_not_reached();
1679}
1680#endif
1681
42071fc1 1682static void gen_ld_asi(DisasContext *dc, DisasASI *da, TCGv dst, TCGv addr)
0425bee5 1683{
c03a0fd1 1684 switch (da->type) {
7ec1e5ea
RH
1685 case GET_ASI_EXCP:
1686 break;
e4dc0052
RH
1687 case GET_ASI_DTWINX: /* Reserved for ldda. */
1688 gen_exception(dc, TT_ILL_INSN);
1689 break;
f0913be0 1690 case GET_ASI_DIRECT:
c03a0fd1 1691 tcg_gen_qemu_ld_tl(dst, addr, da->mem_idx, da->memop | MO_ALIGN);
f0913be0 1692 break;
7ec1e5ea
RH
1693 default:
1694 {
c03a0fd1
RH
1695 TCGv_i32 r_asi = tcg_constant_i32(da->asi);
1696 TCGv_i32 r_mop = tcg_constant_i32(da->memop | MO_ALIGN);
7ec1e5ea
RH
1697
1698 save_state(dc);
22e70060 1699#ifdef TARGET_SPARC64
ad75a51e 1700 gen_helper_ld_asi(dst, tcg_env, addr, r_asi, r_mop);
22e70060 1701#else
7ec1e5ea
RH
1702 {
1703 TCGv_i64 t64 = tcg_temp_new_i64();
ad75a51e 1704 gen_helper_ld_asi(t64, tcg_env, addr, r_asi, r_mop);
7ec1e5ea 1705 tcg_gen_trunc_i64_tl(dst, t64);
7ec1e5ea 1706 }
22e70060 1707#endif
7ec1e5ea
RH
1708 }
1709 break;
1710 }
1a2fb1c0
BS
1711}
1712
42071fc1 1713static void gen_st_asi(DisasContext *dc, DisasASI *da, TCGv src, TCGv addr)
c03a0fd1
RH
1714{
1715 switch (da->type) {
7ec1e5ea
RH
1716 case GET_ASI_EXCP:
1717 break;
c03a0fd1 1718
e4dc0052 1719 case GET_ASI_DTWINX: /* Reserved for stda. */
c03a0fd1
RH
1720 if (TARGET_LONG_BITS == 32) {
1721 gen_exception(dc, TT_ILL_INSN);
1722 break;
1723 } else if (!(dc->def->features & CPU_FEATURE_HYPV)) {
3390537b
AT
1724 /* Pre OpenSPARC CPUs don't have these */
1725 gen_exception(dc, TT_ILL_INSN);
c03a0fd1 1726 break;
3390537b 1727 }
c03a0fd1 1728 /* In OpenSPARC T1+ CPUs TWINX ASIs in store are ST_BLKINIT_ ASIs */
fc0cd867 1729 /* fall through */
c03a0fd1 1730
f0913be0 1731 case GET_ASI_DIRECT:
c03a0fd1 1732 tcg_gen_qemu_st_tl(src, addr, da->mem_idx, da->memop | MO_ALIGN);
f0913be0 1733 break;
c03a0fd1 1734
34810610 1735 case GET_ASI_BCOPY:
c03a0fd1 1736 assert(TARGET_LONG_BITS == 32);
34810610
RH
1737 /* Copy 32 bytes from the address in SRC to ADDR. */
1738 /* ??? The original qemu code suggests 4-byte alignment, dropping
1739 the low bits, but the only place I can see this used is in the
1740 Linux kernel with 32 byte alignment, which would make more sense
1741 as a cacheline-style operation. */
1742 {
1743 TCGv saddr = tcg_temp_new();
1744 TCGv daddr = tcg_temp_new();
00ab7e61 1745 TCGv four = tcg_constant_tl(4);
34810610
RH
1746 TCGv_i32 tmp = tcg_temp_new_i32();
1747 int i;
1748
1749 tcg_gen_andi_tl(saddr, src, -4);
1750 tcg_gen_andi_tl(daddr, addr, -4);
1751 for (i = 0; i < 32; i += 4) {
1752 /* Since the loads and stores are paired, allow the
1753 copy to happen in the host endianness. */
c03a0fd1
RH
1754 tcg_gen_qemu_ld_i32(tmp, saddr, da->mem_idx, MO_UL);
1755 tcg_gen_qemu_st_i32(tmp, daddr, da->mem_idx, MO_UL);
34810610
RH
1756 tcg_gen_add_tl(saddr, saddr, four);
1757 tcg_gen_add_tl(daddr, daddr, four);
1758 }
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 }
2519 if (gen_tcg_cond_reg[a->cond] == TCG_COND_NEVER) {
2520 return false;
2521 }
2522
ab9ffe98 2523 gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
3951b7a8 2524 return advance_jump_cond(dc, &cmp, a->a, a->i);
ab9ffe98
RH
2525}
2526
23ada1b1
RH
2527static bool trans_CALL(DisasContext *dc, arg_CALL *a)
2528{
2529 target_long target = address_mask_i(dc, dc->pc + a->i * 4);
2530
2531 gen_store_gpr(dc, 15, tcg_constant_tl(dc->pc));
2532 gen_mov_pc_npc(dc);
2533 dc->npc = target;
2534 return true;
2535}
2536
45196ea4
RH
2537static bool trans_NCP(DisasContext *dc, arg_NCP *a)
2538{
2539 /*
2540 * For sparc32, always generate the no-coprocessor exception.
2541 * For sparc64, always generate illegal instruction.
2542 */
2543#ifdef TARGET_SPARC64
2544 return false;
2545#else
2546 gen_exception(dc, TT_NCP_INSN);
2547 return true;
2548#endif
2549}
2550
6d2a0768
RH
2551static bool trans_SETHI(DisasContext *dc, arg_SETHI *a)
2552{
2553 /* Special-case %g0 because that's the canonical nop. */
2554 if (a->rd) {
2555 gen_store_gpr(dc, a->rd, tcg_constant_tl((uint32_t)a->i << 10));
2556 }
2557 return advance_pc(dc);
2558}
2559
0faef01b
RH
2560/*
2561 * Major Opcode 10 -- integer, floating-point, vis, and system insns.
2562 */
2563
30376636
RH
2564static bool do_tcc(DisasContext *dc, int cond, int cc,
2565 int rs1, bool imm, int rs2_or_imm)
2566{
2567 int mask = ((dc->def->features & CPU_FEATURE_HYPV) && supervisor(dc)
2568 ? UA2005_HTRAP_MASK : V8_TRAP_MASK);
2569 DisasCompare cmp;
2570 TCGLabel *lab;
2571 TCGv_i32 trap;
2572
2573 /* Trap never. */
2574 if (cond == 0) {
2575 return advance_pc(dc);
2576 }
2577
2578 /*
2579 * Immediate traps are the most common case. Since this value is
2580 * live across the branch, it really pays to evaluate the constant.
2581 */
2582 if (rs1 == 0 && (imm || rs2_or_imm == 0)) {
2583 trap = tcg_constant_i32((rs2_or_imm & mask) + TT_TRAP);
2584 } else {
2585 trap = tcg_temp_new_i32();
2586 tcg_gen_trunc_tl_i32(trap, gen_load_gpr(dc, rs1));
2587 if (imm) {
2588 tcg_gen_addi_i32(trap, trap, rs2_or_imm);
2589 } else {
2590 TCGv_i32 t2 = tcg_temp_new_i32();
2591 tcg_gen_trunc_tl_i32(t2, gen_load_gpr(dc, rs2_or_imm));
2592 tcg_gen_add_i32(trap, trap, t2);
2593 }
2594 tcg_gen_andi_i32(trap, trap, mask);
2595 tcg_gen_addi_i32(trap, trap, TT_TRAP);
2596 }
2597
89527e3a
RH
2598 finishing_insn(dc);
2599
30376636
RH
2600 /* Trap always. */
2601 if (cond == 8) {
2602 save_state(dc);
2603 gen_helper_raise_exception(tcg_env, trap);
2604 dc->base.is_jmp = DISAS_NORETURN;
2605 return true;
2606 }
2607
2608 /* Conditional trap. */
2609 flush_cond(dc);
2610 lab = delay_exceptionv(dc, trap);
2611 gen_compare(&cmp, cc, cond, dc);
c8507ebf 2612 tcg_gen_brcondi_tl(cmp.cond, cmp.c1, cmp.c2, lab);
30376636
RH
2613
2614 return advance_pc(dc);
2615}
2616
2617static bool trans_Tcc_r(DisasContext *dc, arg_Tcc_r *a)
2618{
2619 if (avail_32(dc) && a->cc) {
2620 return false;
2621 }
2622 return do_tcc(dc, a->cond, a->cc, a->rs1, false, a->rs2);
2623}
2624
2625static bool trans_Tcc_i_v7(DisasContext *dc, arg_Tcc_i_v7 *a)
2626{
2627 if (avail_64(dc)) {
2628 return false;
2629 }
2630 return do_tcc(dc, a->cond, 0, a->rs1, true, a->i);
2631}
2632
2633static bool trans_Tcc_i_v9(DisasContext *dc, arg_Tcc_i_v9 *a)
2634{
2635 if (avail_32(dc)) {
2636 return false;
2637 }
2638 return do_tcc(dc, a->cond, a->cc, a->rs1, true, a->i);
2639}
2640
af25071c
RH
2641static bool trans_STBAR(DisasContext *dc, arg_STBAR *a)
2642{
2643 tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC);
2644 return advance_pc(dc);
2645}
2646
2647static bool trans_MEMBAR(DisasContext *dc, arg_MEMBAR *a)
2648{
2649 if (avail_32(dc)) {
2650 return false;
2651 }
2652 if (a->mmask) {
2653 /* Note TCG_MO_* was modeled on sparc64, so mmask matches. */
2654 tcg_gen_mb(a->mmask | TCG_BAR_SC);
2655 }
2656 if (a->cmask) {
2657 /* For #Sync, etc, end the TB to recognize interrupts. */
2658 dc->base.is_jmp = DISAS_EXIT;
2659 }
2660 return advance_pc(dc);
2661}
2662
2663static bool do_rd_special(DisasContext *dc, bool priv, int rd,
2664 TCGv (*func)(DisasContext *, TCGv))
2665{
2666 if (!priv) {
2667 return raise_priv(dc);
2668 }
2669 gen_store_gpr(dc, rd, func(dc, gen_dest_gpr(dc, rd)));
2670 return advance_pc(dc);
2671}
2672
2673static TCGv do_rdy(DisasContext *dc, TCGv dst)
2674{
2675 return cpu_y;
2676}
2677
2678static bool trans_RDY(DisasContext *dc, arg_RDY *a)
2679{
2680 /*
2681 * TODO: Need a feature bit for sparcv8. In the meantime, treat all
2682 * 32-bit cpus like sparcv7, which ignores the rs1 field.
2683 * This matches after all other ASR, so Leon3 Asr17 is handled first.
2684 */
2685 if (avail_64(dc) && a->rs1 != 0) {
2686 return false;
2687 }
2688 return do_rd_special(dc, true, a->rd, do_rdy);
2689}
2690
2691static TCGv do_rd_leon3_config(DisasContext *dc, TCGv dst)
2692{
2693 uint32_t val;
2694
2695 /*
2696 * TODO: There are many more fields to be filled,
2697 * some of which are writable.
2698 */
2699 val = dc->def->nwindows - 1; /* [4:0] NWIN */
2700 val |= 1 << 8; /* [8] V8 */
2701
2702 return tcg_constant_tl(val);
2703}
2704
2705TRANS(RDASR17, ASR17, do_rd_special, true, a->rd, do_rd_leon3_config)
2706
2707static TCGv do_rdccr(DisasContext *dc, TCGv dst)
2708{
af25071c
RH
2709 gen_helper_rdccr(dst, tcg_env);
2710 return dst;
2711}
2712
2713TRANS(RDCCR, 64, do_rd_special, true, a->rd, do_rdccr)
2714
2715static TCGv do_rdasi(DisasContext *dc, TCGv dst)
2716{
2717#ifdef TARGET_SPARC64
2718 return tcg_constant_tl(dc->asi);
2719#else
2720 qemu_build_not_reached();
2721#endif
2722}
2723
2724TRANS(RDASI, 64, do_rd_special, true, a->rd, do_rdasi)
2725
2726static TCGv do_rdtick(DisasContext *dc, TCGv dst)
2727{
2728 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
2729
2730 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick));
2731 if (translator_io_start(&dc->base)) {
2732 dc->base.is_jmp = DISAS_EXIT;
2733 }
2734 gen_helper_tick_get_count(dst, tcg_env, r_tickptr,
2735 tcg_constant_i32(dc->mem_idx));
2736 return dst;
2737}
2738
2739/* TODO: non-priv access only allowed when enabled. */
2740TRANS(RDTICK, 64, do_rd_special, true, a->rd, do_rdtick)
2741
2742static TCGv do_rdpc(DisasContext *dc, TCGv dst)
2743{
2744 return tcg_constant_tl(address_mask_i(dc, dc->pc));
2745}
2746
2747TRANS(RDPC, 64, do_rd_special, true, a->rd, do_rdpc)
2748
2749static TCGv do_rdfprs(DisasContext *dc, TCGv dst)
2750{
2751 tcg_gen_ext_i32_tl(dst, cpu_fprs);
2752 return dst;
2753}
2754
2755TRANS(RDFPRS, 64, do_rd_special, true, a->rd, do_rdfprs)
2756
2757static TCGv do_rdgsr(DisasContext *dc, TCGv dst)
2758{
2759 gen_trap_ifnofpu(dc);
2760 return cpu_gsr;
2761}
2762
2763TRANS(RDGSR, 64, do_rd_special, true, a->rd, do_rdgsr)
2764
2765static TCGv do_rdsoftint(DisasContext *dc, TCGv dst)
2766{
2767 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(softint));
2768 return dst;
2769}
2770
2771TRANS(RDSOFTINT, 64, do_rd_special, supervisor(dc), a->rd, do_rdsoftint)
2772
2773static TCGv do_rdtick_cmpr(DisasContext *dc, TCGv dst)
2774{
577efa45
RH
2775 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(tick_cmpr));
2776 return dst;
af25071c
RH
2777}
2778
2779/* TODO: non-priv access only allowed when enabled. */
2780TRANS(RDTICK_CMPR, 64, do_rd_special, true, a->rd, do_rdtick_cmpr)
2781
2782static TCGv do_rdstick(DisasContext *dc, TCGv dst)
2783{
2784 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
2785
2786 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(stick));
2787 if (translator_io_start(&dc->base)) {
2788 dc->base.is_jmp = DISAS_EXIT;
2789 }
2790 gen_helper_tick_get_count(dst, tcg_env, r_tickptr,
2791 tcg_constant_i32(dc->mem_idx));
2792 return dst;
2793}
2794
2795/* TODO: non-priv access only allowed when enabled. */
2796TRANS(RDSTICK, 64, do_rd_special, true, a->rd, do_rdstick)
2797
2798static TCGv do_rdstick_cmpr(DisasContext *dc, TCGv dst)
2799{
577efa45
RH
2800 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(stick_cmpr));
2801 return dst;
af25071c
RH
2802}
2803
2804/* TODO: supervisor access only allowed when enabled by hypervisor. */
2805TRANS(RDSTICK_CMPR, 64, do_rd_special, supervisor(dc), a->rd, do_rdstick_cmpr)
2806
2807/*
2808 * UltraSPARC-T1 Strand status.
2809 * HYPV check maybe not enough, UA2005 & UA2007 describe
2810 * this ASR as impl. dep
2811 */
2812static TCGv do_rdstrand_status(DisasContext *dc, TCGv dst)
2813{
2814 return tcg_constant_tl(1);
2815}
2816
2817TRANS(RDSTRAND_STATUS, HYPV, do_rd_special, true, a->rd, do_rdstrand_status)
2818
668bb9b7
RH
2819static TCGv do_rdpsr(DisasContext *dc, TCGv dst)
2820{
668bb9b7
RH
2821 gen_helper_rdpsr(dst, tcg_env);
2822 return dst;
2823}
2824
2825TRANS(RDPSR, 32, do_rd_special, supervisor(dc), a->rd, do_rdpsr)
2826
2827static TCGv do_rdhpstate(DisasContext *dc, TCGv dst)
2828{
2829 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hpstate));
2830 return dst;
2831}
2832
2833TRANS(RDHPR_hpstate, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhpstate)
2834
2835static TCGv do_rdhtstate(DisasContext *dc, TCGv dst)
2836{
2837 TCGv_i32 tl = tcg_temp_new_i32();
2838 TCGv_ptr tp = tcg_temp_new_ptr();
2839
2840 tcg_gen_ld_i32(tl, tcg_env, env64_field_offsetof(tl));
2841 tcg_gen_andi_i32(tl, tl, MAXTL_MASK);
2842 tcg_gen_shli_i32(tl, tl, 3);
2843 tcg_gen_ext_i32_ptr(tp, tl);
2844 tcg_gen_add_ptr(tp, tp, tcg_env);
2845
2846 tcg_gen_ld_tl(dst, tp, env64_field_offsetof(htstate));
2847 return dst;
2848}
2849
2850TRANS(RDHPR_htstate, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhtstate)
2851
2852static TCGv do_rdhintp(DisasContext *dc, TCGv dst)
2853{
2da789de
RH
2854 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hintp));
2855 return dst;
668bb9b7
RH
2856}
2857
2858TRANS(RDHPR_hintp, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhintp)
2859
2860static TCGv do_rdhtba(DisasContext *dc, TCGv dst)
2861{
2da789de
RH
2862 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(htba));
2863 return dst;
668bb9b7
RH
2864}
2865
2866TRANS(RDHPR_htba, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhtba)
2867
2868static TCGv do_rdhver(DisasContext *dc, TCGv dst)
2869{
2da789de
RH
2870 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hver));
2871 return dst;
668bb9b7
RH
2872}
2873
2874TRANS(RDHPR_hver, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhver)
2875
2876static TCGv do_rdhstick_cmpr(DisasContext *dc, TCGv dst)
2877{
577efa45
RH
2878 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hstick_cmpr));
2879 return dst;
668bb9b7
RH
2880}
2881
2882TRANS(RDHPR_hstick_cmpr, HYPV, do_rd_special, hypervisor(dc), a->rd,
2883 do_rdhstick_cmpr)
2884
5d617bfb
RH
2885static TCGv do_rdwim(DisasContext *dc, TCGv dst)
2886{
cd6269f7
RH
2887 tcg_gen_ld_tl(dst, tcg_env, env32_field_offsetof(wim));
2888 return dst;
5d617bfb
RH
2889}
2890
2891TRANS(RDWIM, 32, do_rd_special, supervisor(dc), a->rd, do_rdwim)
2892
2893static TCGv do_rdtpc(DisasContext *dc, TCGv dst)
2894{
2895#ifdef TARGET_SPARC64
2896 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
2897
2898 gen_load_trap_state_at_tl(r_tsptr);
2899 tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tpc));
2900 return dst;
2901#else
2902 qemu_build_not_reached();
2903#endif
2904}
2905
2906TRANS(RDPR_tpc, 64, do_rd_special, supervisor(dc), a->rd, do_rdtpc)
2907
2908static TCGv do_rdtnpc(DisasContext *dc, TCGv dst)
2909{
2910#ifdef TARGET_SPARC64
2911 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
2912
2913 gen_load_trap_state_at_tl(r_tsptr);
2914 tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tnpc));
2915 return dst;
2916#else
2917 qemu_build_not_reached();
2918#endif
2919}
2920
2921TRANS(RDPR_tnpc, 64, do_rd_special, supervisor(dc), a->rd, do_rdtnpc)
2922
2923static TCGv do_rdtstate(DisasContext *dc, TCGv dst)
2924{
2925#ifdef TARGET_SPARC64
2926 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
2927
2928 gen_load_trap_state_at_tl(r_tsptr);
2929 tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tstate));
2930 return dst;
2931#else
2932 qemu_build_not_reached();
2933#endif
2934}
2935
2936TRANS(RDPR_tstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdtstate)
2937
2938static TCGv do_rdtt(DisasContext *dc, TCGv dst)
2939{
2940#ifdef TARGET_SPARC64
2941 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
2942
2943 gen_load_trap_state_at_tl(r_tsptr);
2944 tcg_gen_ld32s_tl(dst, r_tsptr, offsetof(trap_state, tt));
2945 return dst;
2946#else
2947 qemu_build_not_reached();
2948#endif
2949}
2950
2951TRANS(RDPR_tt, 64, do_rd_special, supervisor(dc), a->rd, do_rdtt)
2952TRANS(RDPR_tick, 64, do_rd_special, supervisor(dc), a->rd, do_rdtick)
2953
2954static TCGv do_rdtba(DisasContext *dc, TCGv dst)
2955{
2956 return cpu_tbr;
2957}
2958
e8325dc0 2959TRANS(RDTBR, 32, do_rd_special, supervisor(dc), a->rd, do_rdtba)
5d617bfb
RH
2960TRANS(RDPR_tba, 64, do_rd_special, supervisor(dc), a->rd, do_rdtba)
2961
2962static TCGv do_rdpstate(DisasContext *dc, TCGv dst)
2963{
2964 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(pstate));
2965 return dst;
2966}
2967
2968TRANS(RDPR_pstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdpstate)
2969
2970static TCGv do_rdtl(DisasContext *dc, TCGv dst)
2971{
2972 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(tl));
2973 return dst;
2974}
2975
2976TRANS(RDPR_tl, 64, do_rd_special, supervisor(dc), a->rd, do_rdtl)
2977
2978static TCGv do_rdpil(DisasContext *dc, TCGv dst)
2979{
2980 tcg_gen_ld32s_tl(dst, tcg_env, env_field_offsetof(psrpil));
2981 return dst;
2982}
2983
2984TRANS(RDPR_pil, 64, do_rd_special, supervisor(dc), a->rd, do_rdpil)
2985
2986static TCGv do_rdcwp(DisasContext *dc, TCGv dst)
2987{
2988 gen_helper_rdcwp(dst, tcg_env);
2989 return dst;
2990}
2991
2992TRANS(RDPR_cwp, 64, do_rd_special, supervisor(dc), a->rd, do_rdcwp)
2993
2994static TCGv do_rdcansave(DisasContext *dc, TCGv dst)
2995{
2996 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(cansave));
2997 return dst;
2998}
2999
3000TRANS(RDPR_cansave, 64, do_rd_special, supervisor(dc), a->rd, do_rdcansave)
3001
3002static TCGv do_rdcanrestore(DisasContext *dc, TCGv dst)
3003{
3004 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(canrestore));
3005 return dst;
3006}
3007
3008TRANS(RDPR_canrestore, 64, do_rd_special, supervisor(dc), a->rd,
3009 do_rdcanrestore)
3010
3011static TCGv do_rdcleanwin(DisasContext *dc, TCGv dst)
3012{
3013 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(cleanwin));
3014 return dst;
3015}
3016
3017TRANS(RDPR_cleanwin, 64, do_rd_special, supervisor(dc), a->rd, do_rdcleanwin)
3018
3019static TCGv do_rdotherwin(DisasContext *dc, TCGv dst)
3020{
3021 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(otherwin));
3022 return dst;
3023}
3024
3025TRANS(RDPR_otherwin, 64, do_rd_special, supervisor(dc), a->rd, do_rdotherwin)
3026
3027static TCGv do_rdwstate(DisasContext *dc, TCGv dst)
3028{
3029 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(wstate));
3030 return dst;
3031}
3032
3033TRANS(RDPR_wstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdwstate)
3034
3035static TCGv do_rdgl(DisasContext *dc, TCGv dst)
3036{
3037 tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(gl));
3038 return dst;
3039}
3040
3041TRANS(RDPR_gl, GL, do_rd_special, supervisor(dc), a->rd, do_rdgl)
3042
3043/* UA2005 strand status */
3044static TCGv do_rdssr(DisasContext *dc, TCGv dst)
3045{
2da789de
RH
3046 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(ssr));
3047 return dst;
5d617bfb
RH
3048}
3049
3050TRANS(RDPR_strand_status, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdssr)
3051
3052static TCGv do_rdver(DisasContext *dc, TCGv dst)
3053{
2da789de
RH
3054 tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(version));
3055 return dst;
5d617bfb
RH
3056}
3057
3058TRANS(RDPR_ver, 64, do_rd_special, supervisor(dc), a->rd, do_rdver)
3059
e8325dc0
RH
3060static bool trans_FLUSHW(DisasContext *dc, arg_FLUSHW *a)
3061{
3062 if (avail_64(dc)) {
3063 gen_helper_flushw(tcg_env);
3064 return advance_pc(dc);
3065 }
3066 return false;
3067}
3068
0faef01b
RH
3069static bool do_wr_special(DisasContext *dc, arg_r_r_ri *a, bool priv,
3070 void (*func)(DisasContext *, TCGv))
3071{
3072 TCGv src;
3073
3074 /* For simplicity, we under-decoded the rs2 form. */
3075 if (!a->imm && (a->rs2_or_imm & ~0x1f)) {
3076 return false;
3077 }
3078 if (!priv) {
3079 return raise_priv(dc);
3080 }
3081
3082 if (a->rs1 == 0 && (a->imm || a->rs2_or_imm == 0)) {
3083 src = tcg_constant_tl(a->rs2_or_imm);
3084 } else {
3085 TCGv src1 = gen_load_gpr(dc, a->rs1);
3086 if (a->rs2_or_imm == 0) {
3087 src = src1;
3088 } else {
3089 src = tcg_temp_new();
3090 if (a->imm) {
3091 tcg_gen_xori_tl(src, src1, a->rs2_or_imm);
3092 } else {
3093 tcg_gen_xor_tl(src, src1, gen_load_gpr(dc, a->rs2_or_imm));
3094 }
3095 }
3096 }
3097 func(dc, src);
3098 return advance_pc(dc);
3099}
3100
3101static void do_wry(DisasContext *dc, TCGv src)
3102{
3103 tcg_gen_ext32u_tl(cpu_y, src);
3104}
3105
3106TRANS(WRY, ALL, do_wr_special, a, true, do_wry)
3107
3108static void do_wrccr(DisasContext *dc, TCGv src)
3109{
3110 gen_helper_wrccr(tcg_env, src);
3111}
3112
3113TRANS(WRCCR, 64, do_wr_special, a, true, do_wrccr)
3114
3115static void do_wrasi(DisasContext *dc, TCGv src)
3116{
3117 TCGv tmp = tcg_temp_new();
3118
3119 tcg_gen_ext8u_tl(tmp, src);
3120 tcg_gen_st32_tl(tmp, tcg_env, env64_field_offsetof(asi));
3121 /* End TB to notice changed ASI. */
3122 dc->base.is_jmp = DISAS_EXIT;
3123}
3124
3125TRANS(WRASI, 64, do_wr_special, a, true, do_wrasi)
3126
3127static void do_wrfprs(DisasContext *dc, TCGv src)
3128{
3129#ifdef TARGET_SPARC64
3130 tcg_gen_trunc_tl_i32(cpu_fprs, src);
3131 dc->fprs_dirty = 0;
3132 dc->base.is_jmp = DISAS_EXIT;
3133#else
3134 qemu_build_not_reached();
3135#endif
3136}
3137
3138TRANS(WRFPRS, 64, do_wr_special, a, true, do_wrfprs)
3139
3140static void do_wrgsr(DisasContext *dc, TCGv src)
3141{
3142 gen_trap_ifnofpu(dc);
3143 tcg_gen_mov_tl(cpu_gsr, src);
3144}
3145
3146TRANS(WRGSR, 64, do_wr_special, a, true, do_wrgsr)
3147
3148static void do_wrsoftint_set(DisasContext *dc, TCGv src)
3149{
3150 gen_helper_set_softint(tcg_env, src);
3151}
3152
3153TRANS(WRSOFTINT_SET, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_set)
3154
3155static void do_wrsoftint_clr(DisasContext *dc, TCGv src)
3156{
3157 gen_helper_clear_softint(tcg_env, src);
3158}
3159
3160TRANS(WRSOFTINT_CLR, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_clr)
3161
3162static void do_wrsoftint(DisasContext *dc, TCGv src)
3163{
3164 gen_helper_write_softint(tcg_env, src);
3165}
3166
3167TRANS(WRSOFTINT, 64, do_wr_special, a, supervisor(dc), do_wrsoftint)
3168
3169static void do_wrtick_cmpr(DisasContext *dc, TCGv src)
3170{
0faef01b
RH
3171 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3172
577efa45
RH
3173 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(tick_cmpr));
3174 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick));
0faef01b 3175 translator_io_start(&dc->base);
577efa45 3176 gen_helper_tick_set_limit(r_tickptr, src);
0faef01b
RH
3177 /* End TB to handle timer interrupt */
3178 dc->base.is_jmp = DISAS_EXIT;
0faef01b
RH
3179}
3180
3181TRANS(WRTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrtick_cmpr)
3182
3183static void do_wrstick(DisasContext *dc, TCGv src)
3184{
3185#ifdef TARGET_SPARC64
3186 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3187
3188 tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick));
3189 translator_io_start(&dc->base);
3190 gen_helper_tick_set_count(r_tickptr, src);
3191 /* End TB to handle timer interrupt */
3192 dc->base.is_jmp = DISAS_EXIT;
3193#else
3194 qemu_build_not_reached();
3195#endif
3196}
3197
3198TRANS(WRSTICK, 64, do_wr_special, a, supervisor(dc), do_wrstick)
3199
3200static void do_wrstick_cmpr(DisasContext *dc, TCGv src)
3201{
0faef01b
RH
3202 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3203
577efa45
RH
3204 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(stick_cmpr));
3205 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(stick));
0faef01b 3206 translator_io_start(&dc->base);
577efa45 3207 gen_helper_tick_set_limit(r_tickptr, src);
0faef01b
RH
3208 /* End TB to handle timer interrupt */
3209 dc->base.is_jmp = DISAS_EXIT;
0faef01b
RH
3210}
3211
3212TRANS(WRSTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrstick_cmpr)
3213
3214static void do_wrpowerdown(DisasContext *dc, TCGv src)
3215{
89527e3a 3216 finishing_insn(dc);
0faef01b
RH
3217 save_state(dc);
3218 gen_helper_power_down(tcg_env);
3219}
3220
3221TRANS(WRPOWERDOWN, POWERDOWN, do_wr_special, a, supervisor(dc), do_wrpowerdown)
3222
25524734
RH
3223static void do_wrpsr(DisasContext *dc, TCGv src)
3224{
3225 gen_helper_wrpsr(tcg_env, src);
25524734
RH
3226 dc->base.is_jmp = DISAS_EXIT;
3227}
3228
3229TRANS(WRPSR, 32, do_wr_special, a, supervisor(dc), do_wrpsr)
3230
9422278e
RH
3231static void do_wrwim(DisasContext *dc, TCGv src)
3232{
3233 target_ulong mask = MAKE_64BIT_MASK(0, dc->def->nwindows);
cd6269f7
RH
3234 TCGv tmp = tcg_temp_new();
3235
3236 tcg_gen_andi_tl(tmp, src, mask);
3237 tcg_gen_st_tl(tmp, tcg_env, env32_field_offsetof(wim));
9422278e
RH
3238}
3239
3240TRANS(WRWIM, 32, do_wr_special, a, supervisor(dc), do_wrwim)
3241
3242static void do_wrtpc(DisasContext *dc, TCGv src)
3243{
3244#ifdef TARGET_SPARC64
3245 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3246
3247 gen_load_trap_state_at_tl(r_tsptr);
3248 tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tpc));
3249#else
3250 qemu_build_not_reached();
3251#endif
3252}
3253
3254TRANS(WRPR_tpc, 64, do_wr_special, a, supervisor(dc), do_wrtpc)
3255
3256static void do_wrtnpc(DisasContext *dc, TCGv src)
3257{
3258#ifdef TARGET_SPARC64
3259 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3260
3261 gen_load_trap_state_at_tl(r_tsptr);
3262 tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tnpc));
3263#else
3264 qemu_build_not_reached();
3265#endif
3266}
3267
3268TRANS(WRPR_tnpc, 64, do_wr_special, a, supervisor(dc), do_wrtnpc)
3269
3270static void do_wrtstate(DisasContext *dc, TCGv src)
3271{
3272#ifdef TARGET_SPARC64
3273 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3274
3275 gen_load_trap_state_at_tl(r_tsptr);
3276 tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tstate));
3277#else
3278 qemu_build_not_reached();
3279#endif
3280}
3281
3282TRANS(WRPR_tstate, 64, do_wr_special, a, supervisor(dc), do_wrtstate)
3283
3284static void do_wrtt(DisasContext *dc, TCGv src)
3285{
3286#ifdef TARGET_SPARC64
3287 TCGv_ptr r_tsptr = tcg_temp_new_ptr();
3288
3289 gen_load_trap_state_at_tl(r_tsptr);
3290 tcg_gen_st32_tl(src, r_tsptr, offsetof(trap_state, tt));
3291#else
3292 qemu_build_not_reached();
3293#endif
3294}
3295
3296TRANS(WRPR_tt, 64, do_wr_special, a, supervisor(dc), do_wrtt)
3297
3298static void do_wrtick(DisasContext *dc, TCGv src)
3299{
3300 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3301
3302 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick));
3303 translator_io_start(&dc->base);
3304 gen_helper_tick_set_count(r_tickptr, src);
3305 /* End TB to handle timer interrupt */
3306 dc->base.is_jmp = DISAS_EXIT;
3307}
3308
3309TRANS(WRPR_tick, 64, do_wr_special, a, supervisor(dc), do_wrtick)
3310
3311static void do_wrtba(DisasContext *dc, TCGv src)
3312{
3313 tcg_gen_mov_tl(cpu_tbr, src);
3314}
3315
3316TRANS(WRPR_tba, 64, do_wr_special, a, supervisor(dc), do_wrtba)
3317
3318static void do_wrpstate(DisasContext *dc, TCGv src)
3319{
3320 save_state(dc);
3321 if (translator_io_start(&dc->base)) {
3322 dc->base.is_jmp = DISAS_EXIT;
3323 }
3324 gen_helper_wrpstate(tcg_env, src);
3325 dc->npc = DYNAMIC_PC;
3326}
3327
3328TRANS(WRPR_pstate, 64, do_wr_special, a, supervisor(dc), do_wrpstate)
3329
3330static void do_wrtl(DisasContext *dc, TCGv src)
3331{
3332 save_state(dc);
3333 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(tl));
3334 dc->npc = DYNAMIC_PC;
3335}
3336
3337TRANS(WRPR_tl, 64, do_wr_special, a, supervisor(dc), do_wrtl)
3338
3339static void do_wrpil(DisasContext *dc, TCGv src)
3340{
3341 if (translator_io_start(&dc->base)) {
3342 dc->base.is_jmp = DISAS_EXIT;
3343 }
3344 gen_helper_wrpil(tcg_env, src);
3345}
3346
3347TRANS(WRPR_pil, 64, do_wr_special, a, supervisor(dc), do_wrpil)
3348
3349static void do_wrcwp(DisasContext *dc, TCGv src)
3350{
3351 gen_helper_wrcwp(tcg_env, src);
3352}
3353
3354TRANS(WRPR_cwp, 64, do_wr_special, a, supervisor(dc), do_wrcwp)
3355
3356static void do_wrcansave(DisasContext *dc, TCGv src)
3357{
3358 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(cansave));
3359}
3360
3361TRANS(WRPR_cansave, 64, do_wr_special, a, supervisor(dc), do_wrcansave)
3362
3363static void do_wrcanrestore(DisasContext *dc, TCGv src)
3364{
3365 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(canrestore));
3366}
3367
3368TRANS(WRPR_canrestore, 64, do_wr_special, a, supervisor(dc), do_wrcanrestore)
3369
3370static void do_wrcleanwin(DisasContext *dc, TCGv src)
3371{
3372 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(cleanwin));
3373}
3374
3375TRANS(WRPR_cleanwin, 64, do_wr_special, a, supervisor(dc), do_wrcleanwin)
3376
3377static void do_wrotherwin(DisasContext *dc, TCGv src)
3378{
3379 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(otherwin));
3380}
3381
3382TRANS(WRPR_otherwin, 64, do_wr_special, a, supervisor(dc), do_wrotherwin)
3383
3384static void do_wrwstate(DisasContext *dc, TCGv src)
3385{
3386 tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(wstate));
3387}
3388
3389TRANS(WRPR_wstate, 64, do_wr_special, a, supervisor(dc), do_wrwstate)
3390
3391static void do_wrgl(DisasContext *dc, TCGv src)
3392{
3393 gen_helper_wrgl(tcg_env, src);
3394}
3395
3396TRANS(WRPR_gl, GL, do_wr_special, a, supervisor(dc), do_wrgl)
3397
3398/* UA2005 strand status */
3399static void do_wrssr(DisasContext *dc, TCGv src)
3400{
2da789de 3401 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(ssr));
9422278e
RH
3402}
3403
3404TRANS(WRPR_strand_status, HYPV, do_wr_special, a, hypervisor(dc), do_wrssr)
3405
bb97f2f5
RH
3406TRANS(WRTBR, 32, do_wr_special, a, supervisor(dc), do_wrtba)
3407
3408static void do_wrhpstate(DisasContext *dc, TCGv src)
3409{
3410 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hpstate));
3411 dc->base.is_jmp = DISAS_EXIT;
3412}
3413
3414TRANS(WRHPR_hpstate, HYPV, do_wr_special, a, hypervisor(dc), do_wrhpstate)
3415
3416static void do_wrhtstate(DisasContext *dc, TCGv src)
3417{
3418 TCGv_i32 tl = tcg_temp_new_i32();
3419 TCGv_ptr tp = tcg_temp_new_ptr();
3420
3421 tcg_gen_ld_i32(tl, tcg_env, env64_field_offsetof(tl));
3422 tcg_gen_andi_i32(tl, tl, MAXTL_MASK);
3423 tcg_gen_shli_i32(tl, tl, 3);
3424 tcg_gen_ext_i32_ptr(tp, tl);
3425 tcg_gen_add_ptr(tp, tp, tcg_env);
3426
3427 tcg_gen_st_tl(src, tp, env64_field_offsetof(htstate));
3428}
3429
3430TRANS(WRHPR_htstate, HYPV, do_wr_special, a, hypervisor(dc), do_wrhtstate)
3431
3432static void do_wrhintp(DisasContext *dc, TCGv src)
3433{
2da789de 3434 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hintp));
bb97f2f5
RH
3435}
3436
3437TRANS(WRHPR_hintp, HYPV, do_wr_special, a, hypervisor(dc), do_wrhintp)
3438
3439static void do_wrhtba(DisasContext *dc, TCGv src)
3440{
2da789de 3441 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(htba));
bb97f2f5
RH
3442}
3443
3444TRANS(WRHPR_htba, HYPV, do_wr_special, a, hypervisor(dc), do_wrhtba)
3445
3446static void do_wrhstick_cmpr(DisasContext *dc, TCGv src)
3447{
3448 TCGv_ptr r_tickptr = tcg_temp_new_ptr();
3449
577efa45 3450 tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hstick_cmpr));
bb97f2f5
RH
3451 tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(hstick));
3452 translator_io_start(&dc->base);
577efa45 3453 gen_helper_tick_set_limit(r_tickptr, src);
bb97f2f5
RH
3454 /* End TB to handle timer interrupt */
3455 dc->base.is_jmp = DISAS_EXIT;
3456}
3457
3458TRANS(WRHPR_hstick_cmpr, HYPV, do_wr_special, a, hypervisor(dc),
3459 do_wrhstick_cmpr)
3460
25524734
RH
3461static bool do_saved_restored(DisasContext *dc, bool saved)
3462{
3463 if (!supervisor(dc)) {
3464 return raise_priv(dc);
3465 }
3466 if (saved) {
3467 gen_helper_saved(tcg_env);
3468 } else {
3469 gen_helper_restored(tcg_env);
3470 }
3471 return advance_pc(dc);
3472}
3473
3474TRANS(SAVED, 64, do_saved_restored, true)
3475TRANS(RESTORED, 64, do_saved_restored, false)
3476
d3825800
RH
3477static bool trans_NOP(DisasContext *dc, arg_NOP *a)
3478{
3479 return advance_pc(dc);
3480}
3481
5458fd31
RH
3482/*
3483 * TODO: Need a feature bit for sparcv8.
3484 * In the meantime, treat all 32-bit cpus like sparcv7.
3485 */
3486TRANS(NOP_v7, 32, trans_NOP, a)
3487TRANS(NOP_v9, 64, trans_NOP, a)
0faef01b 3488
b597eedc 3489static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a,
428881de 3490 void (*func)(TCGv, TCGv, TCGv),
2a45b736
RH
3491 void (*funci)(TCGv, TCGv, target_long),
3492 bool logic_cc)
428881de
RH
3493{
3494 TCGv dst, src1;
3495
3496 /* For simplicity, we under-decoded the rs2 form. */
3497 if (!a->imm && a->rs2_or_imm & ~0x1f) {
3498 return false;
3499 }
3500
2a45b736
RH
3501 if (logic_cc) {
3502 dst = cpu_cc_N;
428881de
RH
3503 } else {
3504 dst = gen_dest_gpr(dc, a->rd);
3505 }
3506 src1 = gen_load_gpr(dc, a->rs1);
3507
3508 if (a->imm || a->rs2_or_imm == 0) {
3509 if (funci) {
3510 funci(dst, src1, a->rs2_or_imm);
3511 } else {
3512 func(dst, src1, tcg_constant_tl(a->rs2_or_imm));
3513 }
3514 } else {
3515 func(dst, src1, cpu_regs[a->rs2_or_imm]);
3516 }
2a45b736
RH
3517
3518 if (logic_cc) {
3519 if (TARGET_LONG_BITS == 64) {
3520 tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
3521 tcg_gen_movi_tl(cpu_icc_C, 0);
3522 }
3523 tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
3524 tcg_gen_movi_tl(cpu_cc_C, 0);
3525 tcg_gen_movi_tl(cpu_cc_V, 0);
3526 }
3527
428881de 3528 gen_store_gpr(dc, a->rd, dst);
428881de
RH
3529 return advance_pc(dc);
3530}
3531
b597eedc 3532static bool do_arith(DisasContext *dc, arg_r_r_ri_cc *a,
428881de
RH
3533 void (*func)(TCGv, TCGv, TCGv),
3534 void (*funci)(TCGv, TCGv, target_long),
3535 void (*func_cc)(TCGv, TCGv, TCGv))
3536{
3537 if (a->cc) {
b597eedc 3538 return do_arith_int(dc, a, func_cc, NULL, false);
428881de 3539 }
b597eedc 3540 return do_arith_int(dc, a, func, funci, false);
428881de
RH
3541}
3542
3543static bool do_logic(DisasContext *dc, arg_r_r_ri_cc *a,
3544 void (*func)(TCGv, TCGv, TCGv),
3545 void (*funci)(TCGv, TCGv, target_long))
3546{
b597eedc 3547 return do_arith_int(dc, a, func, funci, a->cc);
428881de
RH
3548}
3549
b597eedc
RH
3550TRANS(ADD, ALL, do_arith, a, tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_addcc)
3551TRANS(SUB, ALL, do_arith, a, tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_subcc)
3552TRANS(ADDC, ALL, do_arith, a, gen_op_addc, NULL, gen_op_addccc)
3553TRANS(SUBC, ALL, do_arith, a, gen_op_subc, NULL, gen_op_subccc)
428881de 3554
b597eedc
RH
3555TRANS(TADDcc, ALL, do_arith, a, NULL, NULL, gen_op_taddcc)
3556TRANS(TSUBcc, ALL, do_arith, a, NULL, NULL, gen_op_tsubcc)
3557TRANS(TADDccTV, ALL, do_arith, a, NULL, NULL, gen_op_taddcctv)
3558TRANS(TSUBccTV, ALL, do_arith, a, NULL, NULL, gen_op_tsubcctv)
a9aba13d 3559
428881de
RH
3560TRANS(AND, ALL, do_logic, a, tcg_gen_and_tl, tcg_gen_andi_tl)
3561TRANS(XOR, ALL, do_logic, a, tcg_gen_xor_tl, tcg_gen_xori_tl)
3562TRANS(ANDN, ALL, do_logic, a, tcg_gen_andc_tl, NULL)
3563TRANS(ORN, ALL, do_logic, a, tcg_gen_orc_tl, NULL)
3564TRANS(XORN, ALL, do_logic, a, tcg_gen_eqv_tl, NULL)
3565
b597eedc 3566TRANS(MULX, 64, do_arith, a, tcg_gen_mul_tl, tcg_gen_muli_tl, NULL)
b5372650
RH
3567TRANS(UMUL, MUL, do_logic, a, gen_op_umul, NULL)
3568TRANS(SMUL, MUL, do_logic, a, gen_op_smul, NULL)
b597eedc 3569TRANS(MULScc, ALL, do_arith, a, NULL, NULL, gen_op_mulscc)
22188d7d 3570
b597eedc
RH
3571TRANS(UDIV, DIV, do_arith, a, gen_op_udiv, NULL, gen_op_udivcc)
3572TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL, gen_op_sdivcc)
4ee85ea9 3573
9c6ec5bc 3574/* TODO: Should have feature bit -- comes in with UltraSparc T2. */
b597eedc 3575TRANS(POPC, 64, do_arith, a, gen_op_popc, NULL, NULL)
9c6ec5bc 3576
428881de
RH
3577static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
3578{
3579 /* OR with %g0 is the canonical alias for MOV. */
3580 if (!a->cc && a->rs1 == 0) {
3581 if (a->imm || a->rs2_or_imm == 0) {
3582 gen_store_gpr(dc, a->rd, tcg_constant_tl(a->rs2_or_imm));
3583 } else if (a->rs2_or_imm & ~0x1f) {
3584 /* For simplicity, we under-decoded the rs2 form. */
3585 return false;
3586 } else {
3587 gen_store_gpr(dc, a->rd, cpu_regs[a->rs2_or_imm]);
3588 }
3589 return advance_pc(dc);
3590 }
3591 return do_logic(dc, a, tcg_gen_or_tl, tcg_gen_ori_tl);
3592}
3593
f3141174
RH
3594static bool trans_UDIVX(DisasContext *dc, arg_r_r_ri *a)
3595{
3596 TCGv dst, src1, src2;
3597
3598 if (!avail_64(dc)) {
3599 return false;
3600 }
3601 /* For simplicity, we under-decoded the rs2 form. */
3602 if (!a->imm && a->rs2_or_imm & ~0x1f) {
3603 return false;
3604 }
3605
3606 if (unlikely(a->rs2_or_imm == 0)) {
3607 gen_exception(dc, TT_DIV_ZERO);
3608 return true;
3609 }
3610
3611 if (a->imm) {
3612 src2 = tcg_constant_tl(a->rs2_or_imm);
3613 } else {
3614 TCGLabel *lab;
3615
3616 finishing_insn(dc);
3617 flush_cond(dc);
3618
3619 lab = delay_exception(dc, TT_DIV_ZERO);
3620 src2 = cpu_regs[a->rs2_or_imm];
3621 tcg_gen_brcondi_tl(TCG_COND_EQ, src2, 0, lab);
3622 }
3623
3624 dst = gen_dest_gpr(dc, a->rd);
3625 src1 = gen_load_gpr(dc, a->rs1);
3626
3627 tcg_gen_divu_tl(dst, src1, src2);
3628 gen_store_gpr(dc, a->rd, dst);
3629 return advance_pc(dc);
3630}
3631
3632static bool trans_SDIVX(DisasContext *dc, arg_r_r_ri *a)
3633{
3634 TCGv dst, src1, src2;
3635
3636 if (!avail_64(dc)) {
3637 return false;
3638 }
3639 /* For simplicity, we under-decoded the rs2 form. */
3640 if (!a->imm && a->rs2_or_imm & ~0x1f) {
3641 return false;
3642 }
3643
3644 if (unlikely(a->rs2_or_imm == 0)) {
3645 gen_exception(dc, TT_DIV_ZERO);
3646 return true;
3647 }
3648
3649 dst = gen_dest_gpr(dc, a->rd);
3650 src1 = gen_load_gpr(dc, a->rs1);
3651
3652 if (a->imm) {
3653 if (unlikely(a->rs2_or_imm == -1)) {
3654 tcg_gen_neg_tl(dst, src1);
3655 gen_store_gpr(dc, a->rd, dst);
3656 return advance_pc(dc);
3657 }
3658 src2 = tcg_constant_tl(a->rs2_or_imm);
3659 } else {
3660 TCGLabel *lab;
3661 TCGv t1, t2;
3662
3663 finishing_insn(dc);
3664 flush_cond(dc);
3665
3666 lab = delay_exception(dc, TT_DIV_ZERO);
3667 src2 = cpu_regs[a->rs2_or_imm];
3668 tcg_gen_brcondi_tl(TCG_COND_EQ, src2, 0, lab);
3669
3670 /*
3671 * Need to avoid INT64_MIN / -1, which will trap on x86 host.
3672 * Set SRC2 to 1 as a new divisor, to produce the correct result.
3673 */
3674 t1 = tcg_temp_new();
3675 t2 = tcg_temp_new();
3676 tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src1, (target_long)INT64_MIN);
3677 tcg_gen_setcondi_tl(TCG_COND_EQ, t2, src2, -1);
3678 tcg_gen_and_tl(t1, t1, t2);
3679 tcg_gen_movcond_tl(TCG_COND_NE, t1, t1, tcg_constant_tl(0),
3680 tcg_constant_tl(1), src2);
3681 src2 = t1;
3682 }
3683
3684 tcg_gen_div_tl(dst, src1, src2);
3685 gen_store_gpr(dc, a->rd, dst);
3686 return advance_pc(dc);
3687}
3688
b88ce6f2
RH
3689static bool gen_edge(DisasContext *dc, arg_r_r_r *a,
3690 int width, bool cc, bool left)
3691{
3692 TCGv dst, s1, s2, lo1, lo2;
3693 uint64_t amask, tabl, tabr;
3694 int shift, imask, omask;
3695
3696 dst = gen_dest_gpr(dc, a->rd);
3697 s1 = gen_load_gpr(dc, a->rs1);
3698 s2 = gen_load_gpr(dc, a->rs2);
3699
3700 if (cc) {
f828df74 3701 gen_op_subcc(cpu_cc_N, s1, s2);
b88ce6f2
RH
3702 }
3703
3704 /*
3705 * Theory of operation: there are two tables, left and right (not to
3706 * be confused with the left and right versions of the opcode). These
3707 * are indexed by the low 3 bits of the inputs. To make things "easy",
3708 * these tables are loaded into two constants, TABL and TABR below.
3709 * The operation index = (input & imask) << shift calculates the index
3710 * into the constant, while val = (table >> index) & omask calculates
3711 * the value we're looking for.
3712 */
3713 switch (width) {
3714 case 8:
3715 imask = 0x7;
3716 shift = 3;
3717 omask = 0xff;
3718 if (left) {
3719 tabl = 0x80c0e0f0f8fcfeffULL;
3720 tabr = 0xff7f3f1f0f070301ULL;
3721 } else {
3722 tabl = 0x0103070f1f3f7fffULL;
3723 tabr = 0xfffefcf8f0e0c080ULL;
3724 }
3725 break;
3726 case 16:
3727 imask = 0x6;
3728 shift = 1;
3729 omask = 0xf;
3730 if (left) {
3731 tabl = 0x8cef;
3732 tabr = 0xf731;
3733 } else {
3734 tabl = 0x137f;
3735 tabr = 0xfec8;
3736 }
3737 break;
3738 case 32:
3739 imask = 0x4;
3740 shift = 0;
3741 omask = 0x3;
3742 if (left) {
3743 tabl = (2 << 2) | 3;
3744 tabr = (3 << 2) | 1;
3745 } else {
3746 tabl = (1 << 2) | 3;
3747 tabr = (3 << 2) | 2;
3748 }
3749 break;
3750 default:
3751 abort();
3752 }
3753
3754 lo1 = tcg_temp_new();
3755 lo2 = tcg_temp_new();
3756 tcg_gen_andi_tl(lo1, s1, imask);
3757 tcg_gen_andi_tl(lo2, s2, imask);
3758 tcg_gen_shli_tl(lo1, lo1, shift);
3759 tcg_gen_shli_tl(lo2, lo2, shift);
3760
3761 tcg_gen_shr_tl(lo1, tcg_constant_tl(tabl), lo1);
3762 tcg_gen_shr_tl(lo2, tcg_constant_tl(tabr), lo2);
3763 tcg_gen_andi_tl(lo1, lo1, omask);
3764 tcg_gen_andi_tl(lo2, lo2, omask);
3765
3766 amask = address_mask_i(dc, -8);
3767 tcg_gen_andi_tl(s1, s1, amask);
3768 tcg_gen_andi_tl(s2, s2, amask);
3769
3770 /* Compute dst = (s1 == s2 ? lo1 : lo1 & lo2). */
3771 tcg_gen_and_tl(lo2, lo2, lo1);
3772 tcg_gen_movcond_tl(TCG_COND_EQ, dst, s1, s2, lo1, lo2);
3773
3774 gen_store_gpr(dc, a->rd, dst);
3775 return advance_pc(dc);
3776}
3777
3778TRANS(EDGE8cc, VIS1, gen_edge, a, 8, 1, 0)
3779TRANS(EDGE8Lcc, VIS1, gen_edge, a, 8, 1, 1)
3780TRANS(EDGE16cc, VIS1, gen_edge, a, 16, 1, 0)
3781TRANS(EDGE16Lcc, VIS1, gen_edge, a, 16, 1, 1)
3782TRANS(EDGE32cc, VIS1, gen_edge, a, 32, 1, 0)
3783TRANS(EDGE32Lcc, VIS1, gen_edge, a, 32, 1, 1)
3784
3785TRANS(EDGE8N, VIS2, gen_edge, a, 8, 0, 0)
3786TRANS(EDGE8LN, VIS2, gen_edge, a, 8, 0, 1)
3787TRANS(EDGE16N, VIS2, gen_edge, a, 16, 0, 0)
3788TRANS(EDGE16LN, VIS2, gen_edge, a, 16, 0, 1)
3789TRANS(EDGE32N, VIS2, gen_edge, a, 32, 0, 0)
3790TRANS(EDGE32LN, VIS2, gen_edge, a, 32, 0, 1)
3791
45bfed3b
RH
3792static bool do_rrr(DisasContext *dc, arg_r_r_r *a,
3793 void (*func)(TCGv, TCGv, TCGv))
3794{
3795 TCGv dst = gen_dest_gpr(dc, a->rd);
3796 TCGv src1 = gen_load_gpr(dc, a->rs1);
3797 TCGv src2 = gen_load_gpr(dc, a->rs2);
3798
3799 func(dst, src1, src2);
3800 gen_store_gpr(dc, a->rd, dst);
3801 return advance_pc(dc);
3802}
3803
3804TRANS(ARRAY8, VIS1, do_rrr, a, gen_helper_array8)
3805TRANS(ARRAY16, VIS1, do_rrr, a, gen_op_array16)
3806TRANS(ARRAY32, VIS1, do_rrr, a, gen_op_array32)
3807
9e20ca94
RH
3808static void gen_op_alignaddr(TCGv dst, TCGv s1, TCGv s2)
3809{
3810#ifdef TARGET_SPARC64
3811 TCGv tmp = tcg_temp_new();
3812
3813 tcg_gen_add_tl(tmp, s1, s2);
3814 tcg_gen_andi_tl(dst, tmp, -8);
3815 tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3);
3816#else
3817 g_assert_not_reached();
3818#endif
3819}
3820
3821static void gen_op_alignaddrl(TCGv dst, TCGv s1, TCGv s2)
3822{
3823#ifdef TARGET_SPARC64
3824 TCGv tmp = tcg_temp_new();
3825
3826 tcg_gen_add_tl(tmp, s1, s2);
3827 tcg_gen_andi_tl(dst, tmp, -8);
3828 tcg_gen_neg_tl(tmp, tmp);
3829 tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3);
3830#else
3831 g_assert_not_reached();
3832#endif
3833}
3834
3835TRANS(ALIGNADDR, VIS1, do_rrr, a, gen_op_alignaddr)
3836TRANS(ALIGNADDRL, VIS1, do_rrr, a, gen_op_alignaddrl)
3837
39ca3490
RH
3838static void gen_op_bmask(TCGv dst, TCGv s1, TCGv s2)
3839{
3840#ifdef TARGET_SPARC64
3841 tcg_gen_add_tl(dst, s1, s2);
3842 tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, dst, 32, 32);
3843#else
3844 g_assert_not_reached();
3845#endif
3846}
3847
3848TRANS(BMASK, VIS2, do_rrr, a, gen_op_bmask)
3849
5fc546ee
RH
3850static bool do_shift_r(DisasContext *dc, arg_shiftr *a, bool l, bool u)
3851{
3852 TCGv dst, src1, src2;
3853
3854 /* Reject 64-bit shifts for sparc32. */
3855 if (avail_32(dc) && a->x) {
3856 return false;
3857 }
3858
3859 src2 = tcg_temp_new();
3860 tcg_gen_andi_tl(src2, gen_load_gpr(dc, a->rs2), a->x ? 63 : 31);
3861 src1 = gen_load_gpr(dc, a->rs1);
3862 dst = gen_dest_gpr(dc, a->rd);
3863
3864 if (l) {
3865 tcg_gen_shl_tl(dst, src1, src2);
3866 if (!a->x) {
3867 tcg_gen_ext32u_tl(dst, dst);
3868 }
3869 } else if (u) {
3870 if (!a->x) {
3871 tcg_gen_ext32u_tl(dst, src1);
3872 src1 = dst;
3873 }
3874 tcg_gen_shr_tl(dst, src1, src2);
3875 } else {
3876 if (!a->x) {
3877 tcg_gen_ext32s_tl(dst, src1);
3878 src1 = dst;
3879 }
3880 tcg_gen_sar_tl(dst, src1, src2);
3881 }
3882 gen_store_gpr(dc, a->rd, dst);
3883 return advance_pc(dc);
3884}
3885
3886TRANS(SLL_r, ALL, do_shift_r, a, true, true)
3887TRANS(SRL_r, ALL, do_shift_r, a, false, true)
3888TRANS(SRA_r, ALL, do_shift_r, a, false, false)
3889
3890static bool do_shift_i(DisasContext *dc, arg_shifti *a, bool l, bool u)
3891{
3892 TCGv dst, src1;
3893
3894 /* Reject 64-bit shifts for sparc32. */
3895 if (avail_32(dc) && (a->x || a->i >= 32)) {
3896 return false;
3897 }
3898
3899 src1 = gen_load_gpr(dc, a->rs1);
3900 dst = gen_dest_gpr(dc, a->rd);
3901
3902 if (avail_32(dc) || a->x) {
3903 if (l) {
3904 tcg_gen_shli_tl(dst, src1, a->i);
3905 } else if (u) {
3906 tcg_gen_shri_tl(dst, src1, a->i);
3907 } else {
3908 tcg_gen_sari_tl(dst, src1, a->i);
3909 }
3910 } else {
3911 if (l) {
3912 tcg_gen_deposit_z_tl(dst, src1, a->i, 32 - a->i);
3913 } else if (u) {
3914 tcg_gen_extract_tl(dst, src1, a->i, 32 - a->i);
3915 } else {
3916 tcg_gen_sextract_tl(dst, src1, a->i, 32 - a->i);
3917 }
3918 }
3919 gen_store_gpr(dc, a->rd, dst);
3920 return advance_pc(dc);
3921}
3922
3923TRANS(SLL_i, ALL, do_shift_i, a, true, true)
3924TRANS(SRL_i, ALL, do_shift_i, a, false, true)
3925TRANS(SRA_i, ALL, do_shift_i, a, false, false)
3926
fb4ed7aa
RH
3927static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
3928{
3929 /* For simplicity, we under-decoded the rs2 form. */
3930 if (!imm && rs2_or_imm & ~0x1f) {
3931 return NULL;
3932 }
3933 if (imm || rs2_or_imm == 0) {
3934 return tcg_constant_tl(rs2_or_imm);
3935 } else {
3936 return cpu_regs[rs2_or_imm];
3937 }
3938}
3939
3940static bool do_mov_cond(DisasContext *dc, DisasCompare *cmp, int rd, TCGv src2)
3941{
3942 TCGv dst = gen_load_gpr(dc, rd);
c8507ebf 3943 TCGv c2 = tcg_constant_tl(cmp->c2);
fb4ed7aa 3944
c8507ebf 3945 tcg_gen_movcond_tl(cmp->cond, dst, cmp->c1, c2, src2, dst);
fb4ed7aa
RH
3946 gen_store_gpr(dc, rd, dst);
3947 return advance_pc(dc);
3948}
3949
3950static bool trans_MOVcc(DisasContext *dc, arg_MOVcc *a)
3951{
3952 TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
3953 DisasCompare cmp;
3954
3955 if (src2 == NULL) {
3956 return false;
3957 }
3958 gen_compare(&cmp, a->cc, a->cond, dc);
3959 return do_mov_cond(dc, &cmp, a->rd, src2);
3960}
3961
3962static bool trans_MOVfcc(DisasContext *dc, arg_MOVfcc *a)
3963{
3964 TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
3965 DisasCompare cmp;
3966
3967 if (src2 == NULL) {
3968 return false;
3969 }
3970 gen_fcompare(&cmp, a->cc, a->cond);
3971 return do_mov_cond(dc, &cmp, a->rd, src2);
3972}
3973
3974static bool trans_MOVR(DisasContext *dc, arg_MOVR *a)
3975{
3976 TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
3977 DisasCompare cmp;
3978
3979 if (src2 == NULL) {
3980 return false;
3981 }
3982 gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
3983 return do_mov_cond(dc, &cmp, a->rd, src2);
3984}
3985
86b82fe0
RH
3986static bool do_add_special(DisasContext *dc, arg_r_r_ri *a,
3987 bool (*func)(DisasContext *dc, int rd, TCGv src))
3988{
3989 TCGv src1, sum;
3990
3991 /* For simplicity, we under-decoded the rs2 form. */
3992 if (!a->imm && a->rs2_or_imm & ~0x1f) {
3993 return false;
3994 }
3995
3996 /*
3997 * Always load the sum into a new temporary.
3998 * This is required to capture the value across a window change,
3999 * e.g. SAVE and RESTORE, and may be optimized away otherwise.
4000 */
4001 sum = tcg_temp_new();
4002 src1 = gen_load_gpr(dc, a->rs1);
4003 if (a->imm || a->rs2_or_imm == 0) {
4004 tcg_gen_addi_tl(sum, src1, a->rs2_or_imm);
4005 } else {
4006 tcg_gen_add_tl(sum, src1, cpu_regs[a->rs2_or_imm]);
4007 }
4008 return func(dc, a->rd, sum);
4009}
4010
4011static bool do_jmpl(DisasContext *dc, int rd, TCGv src)
4012{
4013 /*
4014 * Preserve pc across advance, so that we can delay
4015 * the writeback to rd until after src is consumed.
4016 */
4017 target_ulong cur_pc = dc->pc;
4018
4019 gen_check_align(dc, src, 3);
4020
4021 gen_mov_pc_npc(dc);
4022 tcg_gen_mov_tl(cpu_npc, src);
4023 gen_address_mask(dc, cpu_npc);
4024 gen_store_gpr(dc, rd, tcg_constant_tl(cur_pc));
4025
4026 dc->npc = DYNAMIC_PC_LOOKUP;
4027 return true;
4028}
4029
4030TRANS(JMPL, ALL, do_add_special, a, do_jmpl)
4031
4032static bool do_rett(DisasContext *dc, int rd, TCGv src)
4033{
4034 if (!supervisor(dc)) {
4035 return raise_priv(dc);
4036 }
4037
4038 gen_check_align(dc, src, 3);
4039
4040 gen_mov_pc_npc(dc);
4041 tcg_gen_mov_tl(cpu_npc, src);
4042 gen_helper_rett(tcg_env);
4043
4044 dc->npc = DYNAMIC_PC;
4045 return true;
4046}
4047
4048TRANS(RETT, 32, do_add_special, a, do_rett)
4049
4050static bool do_return(DisasContext *dc, int rd, TCGv src)
4051{
4052 gen_check_align(dc, src, 3);
4053
4054 gen_mov_pc_npc(dc);
4055 tcg_gen_mov_tl(cpu_npc, src);
4056 gen_address_mask(dc, cpu_npc);
4057
4058 gen_helper_restore(tcg_env);
4059 dc->npc = DYNAMIC_PC_LOOKUP;
4060 return true;
4061}
4062
4063TRANS(RETURN, 64, do_add_special, a, do_return)
4064
d3825800
RH
4065static bool do_save(DisasContext *dc, int rd, TCGv src)
4066{
4067 gen_helper_save(tcg_env);
4068 gen_store_gpr(dc, rd, src);
4069 return advance_pc(dc);
4070}
4071
4072TRANS(SAVE, ALL, do_add_special, a, do_save)
4073
4074static bool do_restore(DisasContext *dc, int rd, TCGv src)
4075{
4076 gen_helper_restore(tcg_env);
4077 gen_store_gpr(dc, rd, src);
4078 return advance_pc(dc);
4079}
4080
4081TRANS(RESTORE, ALL, do_add_special, a, do_restore)
4082
8f75b8a4
RH
4083static bool do_done_retry(DisasContext *dc, bool done)
4084{
4085 if (!supervisor(dc)) {
4086 return raise_priv(dc);
4087 }
4088 dc->npc = DYNAMIC_PC;
4089 dc->pc = DYNAMIC_PC;
4090 translator_io_start(&dc->base);
4091 if (done) {
4092 gen_helper_done(tcg_env);
4093 } else {
4094 gen_helper_retry(tcg_env);
4095 }
4096 return true;
4097}
4098
4099TRANS(DONE, 64, do_done_retry, true)
4100TRANS(RETRY, 64, do_done_retry, false)
4101
0880d20b
RH
4102/*
4103 * Major opcode 11 -- load and store instructions
4104 */
4105
4106static TCGv gen_ldst_addr(DisasContext *dc, int rs1, bool imm, int rs2_or_imm)
4107{
4108 TCGv addr, tmp = NULL;
4109
4110 /* For simplicity, we under-decoded the rs2 form. */
4111 if (!imm && rs2_or_imm & ~0x1f) {
4112 return NULL;
4113 }
4114
4115 addr = gen_load_gpr(dc, rs1);
4116 if (rs2_or_imm) {
4117 tmp = tcg_temp_new();
4118 if (imm) {
4119 tcg_gen_addi_tl(tmp, addr, rs2_or_imm);
4120 } else {
4121 tcg_gen_add_tl(tmp, addr, cpu_regs[rs2_or_imm]);
4122 }
4123 addr = tmp;
4124 }
4125 if (AM_CHECK(dc)) {
4126 if (!tmp) {
4127 tmp = tcg_temp_new();
4128 }
4129 tcg_gen_ext32u_tl(tmp, addr);
4130 addr = tmp;
4131 }
4132 return addr;
4133}
4134
4135static bool do_ld_gpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
4136{
4137 TCGv reg, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4138 DisasASI da;
4139
4140 if (addr == NULL) {
4141 return false;
4142 }
4143 da = resolve_asi(dc, a->asi, mop);
4144
4145 reg = gen_dest_gpr(dc, a->rd);
42071fc1 4146 gen_ld_asi(dc, &da, reg, addr);
0880d20b
RH
4147 gen_store_gpr(dc, a->rd, reg);
4148 return advance_pc(dc);
4149}
4150
4151TRANS(LDUW, ALL, do_ld_gpr, a, MO_TEUL)
4152TRANS(LDUB, ALL, do_ld_gpr, a, MO_UB)
4153TRANS(LDUH, ALL, do_ld_gpr, a, MO_TEUW)
4154TRANS(LDSB, ALL, do_ld_gpr, a, MO_SB)
4155TRANS(LDSH, ALL, do_ld_gpr, a, MO_TESW)
4156TRANS(LDSW, 64, do_ld_gpr, a, MO_TESL)
4157TRANS(LDX, 64, do_ld_gpr, a, MO_TEUQ)
4158
4159static bool do_st_gpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
4160{
4161 TCGv reg, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4162 DisasASI da;
4163
4164 if (addr == NULL) {
4165 return false;
4166 }
4167 da = resolve_asi(dc, a->asi, mop);
4168
4169 reg = gen_load_gpr(dc, a->rd);
42071fc1 4170 gen_st_asi(dc, &da, reg, addr);
0880d20b
RH
4171 return advance_pc(dc);
4172}
4173
4174TRANS(STW, ALL, do_st_gpr, a, MO_TEUL)
4175TRANS(STB, ALL, do_st_gpr, a, MO_UB)
4176TRANS(STH, ALL, do_st_gpr, a, MO_TEUW)
4177TRANS(STX, 64, do_st_gpr, a, MO_TEUQ)
4178
4179static bool trans_LDD(DisasContext *dc, arg_r_r_ri_asi *a)
4180{
4181 TCGv addr;
4182 DisasASI da;
4183
4184 if (a->rd & 1) {
4185 return false;
4186 }
4187 addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4188 if (addr == NULL) {
4189 return false;
4190 }
4191 da = resolve_asi(dc, a->asi, MO_TEUQ);
42071fc1 4192 gen_ldda_asi(dc, &da, addr, a->rd);
0880d20b
RH
4193 return advance_pc(dc);
4194}
4195
4196static bool trans_STD(DisasContext *dc, arg_r_r_ri_asi *a)
4197{
4198 TCGv addr;
4199 DisasASI da;
4200
4201 if (a->rd & 1) {
4202 return false;
4203 }
4204 addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4205 if (addr == NULL) {
4206 return false;
4207 }
4208 da = resolve_asi(dc, a->asi, MO_TEUQ);
42071fc1 4209 gen_stda_asi(dc, &da, addr, a->rd);
0880d20b
RH
4210 return advance_pc(dc);
4211}
4212
cf07cd1e
RH
4213static bool trans_LDSTUB(DisasContext *dc, arg_r_r_ri_asi *a)
4214{
4215 TCGv addr, reg;
4216 DisasASI da;
4217
4218 addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4219 if (addr == NULL) {
4220 return false;
4221 }
4222 da = resolve_asi(dc, a->asi, MO_UB);
4223
4224 reg = gen_dest_gpr(dc, a->rd);
4225 gen_ldstub_asi(dc, &da, reg, addr);
4226 gen_store_gpr(dc, a->rd, reg);
4227 return advance_pc(dc);
4228}
4229
dca544b9
RH
4230static bool trans_SWAP(DisasContext *dc, arg_r_r_ri_asi *a)
4231{
4232 TCGv addr, dst, src;
4233 DisasASI da;
4234
4235 addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4236 if (addr == NULL) {
4237 return false;
4238 }
4239 da = resolve_asi(dc, a->asi, MO_TEUL);
4240
4241 dst = gen_dest_gpr(dc, a->rd);
4242 src = gen_load_gpr(dc, a->rd);
4243 gen_swap_asi(dc, &da, dst, src, addr);
4244 gen_store_gpr(dc, a->rd, dst);
4245 return advance_pc(dc);
4246}
4247
d0a11d25
RH
4248static bool do_casa(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
4249{
4250 TCGv addr, o, n, c;
4251 DisasASI da;
4252
4253 addr = gen_ldst_addr(dc, a->rs1, true, 0);
4254 if (addr == NULL) {
4255 return false;
4256 }
4257 da = resolve_asi(dc, a->asi, mop);
4258
4259 o = gen_dest_gpr(dc, a->rd);
4260 n = gen_load_gpr(dc, a->rd);
4261 c = gen_load_gpr(dc, a->rs2_or_imm);
4262 gen_cas_asi(dc, &da, o, n, c, addr);
4263 gen_store_gpr(dc, a->rd, o);
4264 return advance_pc(dc);
4265}
4266
4267TRANS(CASA, CASA, do_casa, a, MO_TEUL)
4268TRANS(CASXA, 64, do_casa, a, MO_TEUQ)
4269
06c060d9
RH
4270static bool do_ld_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
4271{
4272 TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4273 DisasASI da;
4274
4275 if (addr == NULL) {
4276 return false;
4277 }
4278 if (gen_trap_ifnofpu(dc)) {
4279 return true;
4280 }
4281 if (sz == MO_128 && gen_trap_float128(dc)) {
4282 return true;
4283 }
4284 da = resolve_asi(dc, a->asi, MO_TE | sz);
287b1152 4285 gen_ldf_asi(dc, &da, sz, addr, a->rd);
06c060d9
RH
4286 gen_update_fprs_dirty(dc, a->rd);
4287 return advance_pc(dc);
4288}
4289
4290TRANS(LDF, ALL, do_ld_fpr, a, MO_32)
4291TRANS(LDDF, ALL, do_ld_fpr, a, MO_64)
4292TRANS(LDQF, ALL, do_ld_fpr, a, MO_128)
4293
287b1152
RH
4294TRANS(LDFA, 64, do_ld_fpr, a, MO_32)
4295TRANS(LDDFA, 64, do_ld_fpr, a, MO_64)
4296TRANS(LDQFA, 64, do_ld_fpr, a, MO_128)
4297
06c060d9
RH
4298static bool do_st_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
4299{
4300 TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4301 DisasASI da;
4302
4303 if (addr == NULL) {
4304 return false;
4305 }
4306 if (gen_trap_ifnofpu(dc)) {
4307 return true;
4308 }
4309 if (sz == MO_128 && gen_trap_float128(dc)) {
4310 return true;
4311 }
4312 da = resolve_asi(dc, a->asi, MO_TE | sz);
287b1152 4313 gen_stf_asi(dc, &da, sz, addr, a->rd);
06c060d9
RH
4314 return advance_pc(dc);
4315}
4316
4317TRANS(STF, ALL, do_st_fpr, a, MO_32)
4318TRANS(STDF, ALL, do_st_fpr, a, MO_64)
4319TRANS(STQF, ALL, do_st_fpr, a, MO_128)
4320
287b1152
RH
4321TRANS(STFA, 64, do_st_fpr, a, MO_32)
4322TRANS(STDFA, 64, do_st_fpr, a, MO_64)
4323TRANS(STQFA, 64, do_st_fpr, a, MO_128)
4324
06c060d9
RH
4325static bool trans_STDFQ(DisasContext *dc, arg_STDFQ *a)
4326{
4327 if (!avail_32(dc)) {
4328 return false;
4329 }
4330 if (!supervisor(dc)) {
4331 return raise_priv(dc);
4332 }
4333 if (gen_trap_ifnofpu(dc)) {
4334 return true;
4335 }
4336 gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
4337 return true;
4338}
4339
da681406
RH
4340static bool do_ldfsr(DisasContext *dc, arg_r_r_ri *a, MemOp mop,
4341 target_ulong new_mask, target_ulong old_mask)
3d3c0673 4342{
da681406 4343 TCGv tmp, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
3d3c0673
RH
4344 if (addr == NULL) {
4345 return false;
4346 }
4347 if (gen_trap_ifnofpu(dc)) {
4348 return true;
4349 }
da681406
RH
4350 tmp = tcg_temp_new();
4351 tcg_gen_qemu_ld_tl(tmp, addr, dc->mem_idx, mop | MO_ALIGN);
4352 tcg_gen_andi_tl(tmp, tmp, new_mask);
4353 tcg_gen_andi_tl(cpu_fsr, cpu_fsr, old_mask);
4354 tcg_gen_or_tl(cpu_fsr, cpu_fsr, tmp);
4355 gen_helper_set_fsr(tcg_env, cpu_fsr);
3d3c0673
RH
4356 return advance_pc(dc);
4357}
4358
da681406
RH
4359TRANS(LDFSR, ALL, do_ldfsr, a, MO_TEUL, FSR_LDFSR_MASK, FSR_LDFSR_OLDMASK)
4360TRANS(LDXFSR, 64, do_ldfsr, a, MO_TEUQ, FSR_LDXFSR_MASK, FSR_LDXFSR_OLDMASK)
3d3c0673
RH
4361
4362static bool do_stfsr(DisasContext *dc, arg_r_r_ri *a, MemOp mop)
4363{
4364 TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
4365 if (addr == NULL) {
4366 return false;
4367 }
4368 if (gen_trap_ifnofpu(dc)) {
4369 return true;
4370 }
4371 tcg_gen_qemu_st_tl(cpu_fsr, addr, dc->mem_idx, mop | MO_ALIGN);
4372 return advance_pc(dc);
4373}
4374
4375TRANS(STFSR, ALL, do_stfsr, a, MO_TEUL)
4376TRANS(STXFSR, 64, do_stfsr, a, MO_TEUQ)
4377
3a38260e
RH
4378static bool do_fc(DisasContext *dc, int rd, bool c)
4379{
4380 uint64_t mask;
4381
4382 if (gen_trap_ifnofpu(dc)) {
4383 return true;
4384 }
4385
4386 if (rd & 1) {
4387 mask = MAKE_64BIT_MASK(0, 32);
4388 } else {
4389 mask = MAKE_64BIT_MASK(32, 32);
4390 }
4391 if (c) {
4392 tcg_gen_ori_i64(cpu_fpr[rd / 2], cpu_fpr[rd / 2], mask);
4393 } else {
4394 tcg_gen_andi_i64(cpu_fpr[rd / 2], cpu_fpr[rd / 2], ~mask);
4395 }
4396 gen_update_fprs_dirty(dc, rd);
4397 return advance_pc(dc);
4398}
4399
4400TRANS(FZEROs, VIS1, do_fc, a->rd, 0)
4401TRANS(FONEs, VIS1, do_fc, a->rd, 1)
4402
4403static bool do_dc(DisasContext *dc, int rd, int64_t c)
4404{
4405 if (gen_trap_ifnofpu(dc)) {
4406 return true;
4407 }
4408
4409 tcg_gen_movi_i64(cpu_fpr[rd / 2], c);
4410 gen_update_fprs_dirty(dc, rd);
4411 return advance_pc(dc);
4412}
4413
4414TRANS(FZEROd, VIS1, do_dc, a->rd, 0)
4415TRANS(FONEd, VIS1, do_dc, a->rd, -1)
4416
baf3dbf2
RH
4417static bool do_ff(DisasContext *dc, arg_r_r *a,
4418 void (*func)(TCGv_i32, TCGv_i32))
4419{
4420 TCGv_i32 tmp;
4421
4422 if (gen_trap_ifnofpu(dc)) {
4423 return true;
4424 }
4425
4426 tmp = gen_load_fpr_F(dc, a->rs);
4427 func(tmp, tmp);
4428 gen_store_fpr_F(dc, a->rd, tmp);
4429 return advance_pc(dc);
4430}
4431
4432TRANS(FMOVs, ALL, do_ff, a, gen_op_fmovs)
4433TRANS(FNEGs, ALL, do_ff, a, gen_op_fnegs)
4434TRANS(FABSs, ALL, do_ff, a, gen_op_fabss)
4435TRANS(FSRCs, VIS1, do_ff, a, tcg_gen_mov_i32)
4436TRANS(FNOTs, VIS1, do_ff, a, tcg_gen_not_i32)
4437
2f722641
RH
4438static bool do_fd(DisasContext *dc, arg_r_r *a,
4439 void (*func)(TCGv_i32, TCGv_i64))
4440{
4441 TCGv_i32 dst;
4442 TCGv_i64 src;
4443
4444 if (gen_trap_ifnofpu(dc)) {
4445 return true;
4446 }
4447
4448 dst = gen_dest_fpr_F(dc);
4449 src = gen_load_fpr_D(dc, a->rs);
4450 func(dst, src);
4451 gen_store_fpr_F(dc, a->rd, dst);
4452 return advance_pc(dc);
4453}
4454
4455TRANS(FPACK16, VIS1, do_fd, a, gen_op_fpack16)
4456TRANS(FPACKFIX, VIS1, do_fd, a, gen_op_fpackfix)
4457
119cb94f
RH
4458static bool do_env_ff(DisasContext *dc, arg_r_r *a,
4459 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
4460{
4461 TCGv_i32 tmp;
4462
4463 if (gen_trap_ifnofpu(dc)) {
4464 return true;
4465 }
4466
4467 gen_op_clear_ieee_excp_and_FTT();
4468 tmp = gen_load_fpr_F(dc, a->rs);
4469 func(tmp, tcg_env, tmp);
4470 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4471 gen_store_fpr_F(dc, a->rd, tmp);
4472 return advance_pc(dc);
4473}
4474
4475TRANS(FSQRTs, ALL, do_env_ff, a, gen_helper_fsqrts)
4476TRANS(FiTOs, ALL, do_env_ff, a, gen_helper_fitos)
4477TRANS(FsTOi, ALL, do_env_ff, a, gen_helper_fstoi)
4478
8c94bcd8
RH
4479static bool do_env_fd(DisasContext *dc, arg_r_r *a,
4480 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
4481{
4482 TCGv_i32 dst;
4483 TCGv_i64 src;
4484
4485 if (gen_trap_ifnofpu(dc)) {
4486 return true;
4487 }
4488
4489 gen_op_clear_ieee_excp_and_FTT();
4490 dst = gen_dest_fpr_F(dc);
4491 src = gen_load_fpr_D(dc, a->rs);
4492 func(dst, tcg_env, src);
4493 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4494 gen_store_fpr_F(dc, a->rd, dst);
4495 return advance_pc(dc);
4496}
4497
4498TRANS(FdTOs, ALL, do_env_fd, a, gen_helper_fdtos)
4499TRANS(FdTOi, ALL, do_env_fd, a, gen_helper_fdtoi)
4500TRANS(FxTOs, 64, do_env_fd, a, gen_helper_fxtos)
4501
c6d83e4f
RH
4502static bool do_dd(DisasContext *dc, arg_r_r *a,
4503 void (*func)(TCGv_i64, TCGv_i64))
4504{
4505 TCGv_i64 dst, src;
4506
4507 if (gen_trap_ifnofpu(dc)) {
4508 return true;
4509 }
4510
4511 dst = gen_dest_fpr_D(dc, a->rd);
4512 src = gen_load_fpr_D(dc, a->rs);
4513 func(dst, src);
4514 gen_store_fpr_D(dc, a->rd, dst);
4515 return advance_pc(dc);
4516}
4517
4518TRANS(FMOVd, 64, do_dd, a, gen_op_fmovd)
4519TRANS(FNEGd, 64, do_dd, a, gen_op_fnegd)
4520TRANS(FABSd, 64, do_dd, a, gen_op_fabsd)
4521TRANS(FSRCd, VIS1, do_dd, a, tcg_gen_mov_i64)
4522TRANS(FNOTd, VIS1, do_dd, a, tcg_gen_not_i64)
4523
8aa418b3
RH
4524static bool do_env_dd(DisasContext *dc, arg_r_r *a,
4525 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
4526{
4527 TCGv_i64 dst, src;
4528
4529 if (gen_trap_ifnofpu(dc)) {
4530 return true;
4531 }
4532
4533 gen_op_clear_ieee_excp_and_FTT();
4534 dst = gen_dest_fpr_D(dc, a->rd);
4535 src = gen_load_fpr_D(dc, a->rs);
4536 func(dst, tcg_env, src);
4537 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4538 gen_store_fpr_D(dc, a->rd, dst);
4539 return advance_pc(dc);
4540}
4541
4542TRANS(FSQRTd, ALL, do_env_dd, a, gen_helper_fsqrtd)
4543TRANS(FxTOd, 64, do_env_dd, a, gen_helper_fxtod)
4544TRANS(FdTOx, 64, do_env_dd, a, gen_helper_fdtox)
4545
199d43ef
RH
4546static bool do_env_df(DisasContext *dc, arg_r_r *a,
4547 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
4548{
4549 TCGv_i64 dst;
4550 TCGv_i32 src;
4551
4552 if (gen_trap_ifnofpu(dc)) {
4553 return true;
4554 }
4555
4556 gen_op_clear_ieee_excp_and_FTT();
4557 dst = gen_dest_fpr_D(dc, a->rd);
4558 src = gen_load_fpr_F(dc, a->rs);
4559 func(dst, tcg_env, src);
4560 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4561 gen_store_fpr_D(dc, a->rd, dst);
4562 return advance_pc(dc);
4563}
4564
4565TRANS(FiTOd, ALL, do_env_df, a, gen_helper_fitod)
4566TRANS(FsTOd, ALL, do_env_df, a, gen_helper_fstod)
4567TRANS(FsTOx, 64, do_env_df, a, gen_helper_fstox)
4568
f4e18df5
RH
4569static bool trans_FMOVq(DisasContext *dc, arg_FMOVq *a)
4570{
4571 int rd, rs;
4572
4573 if (!avail_64(dc)) {
4574 return false;
4575 }
4576 if (gen_trap_ifnofpu(dc)) {
4577 return true;
4578 }
4579 if (gen_trap_float128(dc)) {
4580 return true;
4581 }
4582
4583 gen_op_clear_ieee_excp_and_FTT();
4584 rd = QFPREG(a->rd);
4585 rs = QFPREG(a->rs);
4586 tcg_gen_mov_i64(cpu_fpr[rd / 2], cpu_fpr[rs / 2]);
4587 tcg_gen_mov_i64(cpu_fpr[rd / 2 + 1], cpu_fpr[rs / 2 + 1]);
4588 gen_update_fprs_dirty(dc, rd);
4589 return advance_pc(dc);
4590}
4591
4592static bool do_qq(DisasContext *dc, arg_r_r *a,
4593 void (*func)(TCGv_env))
4594{
4595 if (gen_trap_ifnofpu(dc)) {
4596 return true;
4597 }
4598 if (gen_trap_float128(dc)) {
4599 return true;
4600 }
4601
4602 gen_op_clear_ieee_excp_and_FTT();
4603 gen_op_load_fpr_QT1(QFPREG(a->rs));
4604 func(tcg_env);
4605 gen_op_store_QT0_fpr(QFPREG(a->rd));
4606 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4607 return advance_pc(dc);
4608}
4609
4610TRANS(FNEGq, 64, do_qq, a, gen_helper_fnegq)
4611TRANS(FABSq, 64, do_qq, a, gen_helper_fabsq)
4612
c995216b
RH
4613static bool do_env_qq(DisasContext *dc, arg_r_r *a,
4614 void (*func)(TCGv_env))
4615{
4616 if (gen_trap_ifnofpu(dc)) {
4617 return true;
4618 }
4619 if (gen_trap_float128(dc)) {
4620 return true;
4621 }
4622
4623 gen_op_clear_ieee_excp_and_FTT();
4624 gen_op_load_fpr_QT1(QFPREG(a->rs));
4625 func(tcg_env);
4626 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4627 gen_op_store_QT0_fpr(QFPREG(a->rd));
4628 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4629 return advance_pc(dc);
4630}
4631
4632TRANS(FSQRTq, ALL, do_env_qq, a, gen_helper_fsqrtq)
4633
bd9c5c42
RH
4634static bool do_env_fq(DisasContext *dc, arg_r_r *a,
4635 void (*func)(TCGv_i32, TCGv_env))
4636{
4637 TCGv_i32 dst;
4638
4639 if (gen_trap_ifnofpu(dc)) {
4640 return true;
4641 }
4642 if (gen_trap_float128(dc)) {
4643 return true;
4644 }
4645
4646 gen_op_clear_ieee_excp_and_FTT();
4647 gen_op_load_fpr_QT1(QFPREG(a->rs));
4648 dst = gen_dest_fpr_F(dc);
4649 func(dst, tcg_env);
4650 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4651 gen_store_fpr_F(dc, a->rd, dst);
4652 return advance_pc(dc);
4653}
4654
4655TRANS(FqTOs, ALL, do_env_fq, a, gen_helper_fqtos)
4656TRANS(FqTOi, ALL, do_env_fq, a, gen_helper_fqtoi)
4657
1617586f
RH
4658static bool do_env_dq(DisasContext *dc, arg_r_r *a,
4659 void (*func)(TCGv_i64, TCGv_env))
4660{
4661 TCGv_i64 dst;
4662
4663 if (gen_trap_ifnofpu(dc)) {
4664 return true;
4665 }
4666 if (gen_trap_float128(dc)) {
4667 return true;
4668 }
4669
4670 gen_op_clear_ieee_excp_and_FTT();
4671 gen_op_load_fpr_QT1(QFPREG(a->rs));
4672 dst = gen_dest_fpr_D(dc, a->rd);
4673 func(dst, tcg_env);
4674 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4675 gen_store_fpr_D(dc, a->rd, dst);
4676 return advance_pc(dc);
4677}
4678
4679TRANS(FqTOd, ALL, do_env_dq, a, gen_helper_fqtod)
4680TRANS(FqTOx, 64, do_env_dq, a, gen_helper_fqtox)
4681
13ebcc77
RH
4682static bool do_env_qf(DisasContext *dc, arg_r_r *a,
4683 void (*func)(TCGv_env, TCGv_i32))
4684{
4685 TCGv_i32 src;
4686
4687 if (gen_trap_ifnofpu(dc)) {
4688 return true;
4689 }
4690 if (gen_trap_float128(dc)) {
4691 return true;
4692 }
4693
4694 gen_op_clear_ieee_excp_and_FTT();
4695 src = gen_load_fpr_F(dc, a->rs);
4696 func(tcg_env, src);
4697 gen_op_store_QT0_fpr(QFPREG(a->rd));
4698 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4699 return advance_pc(dc);
4700}
4701
4702TRANS(FiTOq, ALL, do_env_qf, a, gen_helper_fitoq)
4703TRANS(FsTOq, ALL, do_env_qf, a, gen_helper_fstoq)
4704
7b8e3e1a
RH
4705static bool do_env_qd(DisasContext *dc, arg_r_r *a,
4706 void (*func)(TCGv_env, TCGv_i64))
4707{
4708 TCGv_i64 src;
4709
4710 if (gen_trap_ifnofpu(dc)) {
4711 return true;
4712 }
4713 if (gen_trap_float128(dc)) {
4714 return true;
4715 }
4716
4717 gen_op_clear_ieee_excp_and_FTT();
4718 src = gen_load_fpr_D(dc, a->rs);
4719 func(tcg_env, src);
4720 gen_op_store_QT0_fpr(QFPREG(a->rd));
4721 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4722 return advance_pc(dc);
4723}
4724
4725TRANS(FdTOq, ALL, do_env_qd, a, gen_helper_fdtoq)
4726TRANS(FxTOq, 64, do_env_qd, a, gen_helper_fxtoq)
4727
7f10b52f
RH
4728static bool do_fff(DisasContext *dc, arg_r_r_r *a,
4729 void (*func)(TCGv_i32, TCGv_i32, TCGv_i32))
4730{
4731 TCGv_i32 src1, src2;
4732
4733 if (gen_trap_ifnofpu(dc)) {
4734 return true;
4735 }
4736
4737 src1 = gen_load_fpr_F(dc, a->rs1);
4738 src2 = gen_load_fpr_F(dc, a->rs2);
4739 func(src1, src1, src2);
4740 gen_store_fpr_F(dc, a->rd, src1);
4741 return advance_pc(dc);
4742}
4743
4744TRANS(FPADD16s, VIS1, do_fff, a, tcg_gen_vec_add16_i32)
4745TRANS(FPADD32s, VIS1, do_fff, a, tcg_gen_add_i32)
4746TRANS(FPSUB16s, VIS1, do_fff, a, tcg_gen_vec_sub16_i32)
4747TRANS(FPSUB32s, VIS1, do_fff, a, tcg_gen_sub_i32)
4748TRANS(FNORs, VIS1, do_fff, a, tcg_gen_nor_i32)
4749TRANS(FANDNOTs, VIS1, do_fff, a, tcg_gen_andc_i32)
4750TRANS(FXORs, VIS1, do_fff, a, tcg_gen_xor_i32)
4751TRANS(FNANDs, VIS1, do_fff, a, tcg_gen_nand_i32)
4752TRANS(FANDs, VIS1, do_fff, a, tcg_gen_and_i32)
4753TRANS(FXNORs, VIS1, do_fff, a, tcg_gen_eqv_i32)
4754TRANS(FORNOTs, VIS1, do_fff, a, tcg_gen_orc_i32)
4755TRANS(FORs, VIS1, do_fff, a, tcg_gen_or_i32)
4756
c1514961
RH
4757static bool do_env_fff(DisasContext *dc, arg_r_r_r *a,
4758 void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
4759{
4760 TCGv_i32 src1, src2;
4761
4762 if (gen_trap_ifnofpu(dc)) {
4763 return true;
4764 }
4765
4766 gen_op_clear_ieee_excp_and_FTT();
4767 src1 = gen_load_fpr_F(dc, a->rs1);
4768 src2 = gen_load_fpr_F(dc, a->rs2);
4769 func(src1, tcg_env, src1, src2);
4770 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4771 gen_store_fpr_F(dc, a->rd, src1);
4772 return advance_pc(dc);
4773}
4774
4775TRANS(FADDs, ALL, do_env_fff, a, gen_helper_fadds)
4776TRANS(FSUBs, ALL, do_env_fff, a, gen_helper_fsubs)
4777TRANS(FMULs, ALL, do_env_fff, a, gen_helper_fmuls)
4778TRANS(FDIVs, ALL, do_env_fff, a, gen_helper_fdivs)
4779
e06c9f83
RH
4780static bool do_ddd(DisasContext *dc, arg_r_r_r *a,
4781 void (*func)(TCGv_i64, TCGv_i64, TCGv_i64))
4782{
4783 TCGv_i64 dst, src1, src2;
4784
4785 if (gen_trap_ifnofpu(dc)) {
4786 return true;
4787 }
4788
4789 dst = gen_dest_fpr_D(dc, a->rd);
4790 src1 = gen_load_fpr_D(dc, a->rs1);
4791 src2 = gen_load_fpr_D(dc, a->rs2);
4792 func(dst, src1, src2);
4793 gen_store_fpr_D(dc, a->rd, dst);
4794 return advance_pc(dc);
4795}
4796
4797TRANS(FMUL8x16, VIS1, do_ddd, a, gen_helper_fmul8x16)
4798TRANS(FMUL8x16AU, VIS1, do_ddd, a, gen_helper_fmul8x16au)
4799TRANS(FMUL8x16AL, VIS1, do_ddd, a, gen_helper_fmul8x16al)
4800TRANS(FMUL8SUx16, VIS1, do_ddd, a, gen_helper_fmul8sux16)
4801TRANS(FMUL8ULx16, VIS1, do_ddd, a, gen_helper_fmul8ulx16)
4802TRANS(FMULD8SUx16, VIS1, do_ddd, a, gen_helper_fmuld8sux16)
4803TRANS(FMULD8ULx16, VIS1, do_ddd, a, gen_helper_fmuld8ulx16)
4804TRANS(FPMERGE, VIS1, do_ddd, a, gen_helper_fpmerge)
4805TRANS(FEXPAND, VIS1, do_ddd, a, gen_helper_fexpand)
4806
4807TRANS(FPADD16, VIS1, do_ddd, a, tcg_gen_vec_add16_i64)
4808TRANS(FPADD32, VIS1, do_ddd, a, tcg_gen_vec_add32_i64)
4809TRANS(FPSUB16, VIS1, do_ddd, a, tcg_gen_vec_sub16_i64)
4810TRANS(FPSUB32, VIS1, do_ddd, a, tcg_gen_vec_sub32_i64)
4811TRANS(FNORd, VIS1, do_ddd, a, tcg_gen_nor_i64)
4812TRANS(FANDNOTd, VIS1, do_ddd, a, tcg_gen_andc_i64)
4813TRANS(FXORd, VIS1, do_ddd, a, tcg_gen_xor_i64)
4814TRANS(FNANDd, VIS1, do_ddd, a, tcg_gen_nand_i64)
4815TRANS(FANDd, VIS1, do_ddd, a, tcg_gen_and_i64)
4816TRANS(FXNORd, VIS1, do_ddd, a, tcg_gen_eqv_i64)
4817TRANS(FORNOTd, VIS1, do_ddd, a, tcg_gen_orc_i64)
4818TRANS(FORd, VIS1, do_ddd, a, tcg_gen_or_i64)
4819
4b6edc0a
RH
4820TRANS(FPACK32, VIS1, do_ddd, a, gen_op_fpack32)
4821TRANS(FALIGNDATAg, VIS1, do_ddd, a, gen_op_faligndata)
4822TRANS(BSHUFFLE, VIS2, do_ddd, a, gen_op_bshuffle)
4823
e2fa6bd1
RH
4824static bool do_rdd(DisasContext *dc, arg_r_r_r *a,
4825 void (*func)(TCGv, TCGv_i64, TCGv_i64))
4826{
4827 TCGv_i64 src1, src2;
4828 TCGv dst;
4829
4830 if (gen_trap_ifnofpu(dc)) {
4831 return true;
4832 }
4833
4834 dst = gen_dest_gpr(dc, a->rd);
4835 src1 = gen_load_fpr_D(dc, a->rs1);
4836 src2 = gen_load_fpr_D(dc, a->rs2);
4837 func(dst, src1, src2);
4838 gen_store_gpr(dc, a->rd, dst);
4839 return advance_pc(dc);
4840}
4841
4842TRANS(FPCMPLE16, VIS1, do_rdd, a, gen_helper_fcmple16)
4843TRANS(FPCMPNE16, VIS1, do_rdd, a, gen_helper_fcmpne16)
4844TRANS(FPCMPGT16, VIS1, do_rdd, a, gen_helper_fcmpgt16)
4845TRANS(FPCMPEQ16, VIS1, do_rdd, a, gen_helper_fcmpeq16)
4846
4847TRANS(FPCMPLE32, VIS1, do_rdd, a, gen_helper_fcmple32)
4848TRANS(FPCMPNE32, VIS1, do_rdd, a, gen_helper_fcmpne32)
4849TRANS(FPCMPGT32, VIS1, do_rdd, a, gen_helper_fcmpgt32)
4850TRANS(FPCMPEQ32, VIS1, do_rdd, a, gen_helper_fcmpeq32)
4851
f2a59b0a
RH
4852static bool do_env_ddd(DisasContext *dc, arg_r_r_r *a,
4853 void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
4854{
4855 TCGv_i64 dst, src1, src2;
4856
4857 if (gen_trap_ifnofpu(dc)) {
4858 return true;
4859 }
4860
4861 gen_op_clear_ieee_excp_and_FTT();
4862 dst = gen_dest_fpr_D(dc, a->rd);
4863 src1 = gen_load_fpr_D(dc, a->rs1);
4864 src2 = gen_load_fpr_D(dc, a->rs2);
4865 func(dst, tcg_env, src1, src2);
4866 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4867 gen_store_fpr_D(dc, a->rd, dst);
4868 return advance_pc(dc);
4869}
4870
4871TRANS(FADDd, ALL, do_env_ddd, a, gen_helper_faddd)
4872TRANS(FSUBd, ALL, do_env_ddd, a, gen_helper_fsubd)
4873TRANS(FMULd, ALL, do_env_ddd, a, gen_helper_fmuld)
4874TRANS(FDIVd, ALL, do_env_ddd, a, gen_helper_fdivd)
4875
ff4c711b
RH
4876static bool trans_FsMULd(DisasContext *dc, arg_r_r_r *a)
4877{
4878 TCGv_i64 dst;
4879 TCGv_i32 src1, src2;
4880
4881 if (gen_trap_ifnofpu(dc)) {
4882 return true;
4883 }
4884 if (!(dc->def->features & CPU_FEATURE_FSMULD)) {
4885 return raise_unimpfpop(dc);
4886 }
4887
4888 gen_op_clear_ieee_excp_and_FTT();
4889 dst = gen_dest_fpr_D(dc, a->rd);
4890 src1 = gen_load_fpr_F(dc, a->rs1);
4891 src2 = gen_load_fpr_F(dc, a->rs2);
4892 gen_helper_fsmuld(dst, tcg_env, src1, src2);
4893 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4894 gen_store_fpr_D(dc, a->rd, dst);
4895 return advance_pc(dc);
4896}
4897
afb04344
RH
4898static bool do_dddd(DisasContext *dc, arg_r_r_r *a,
4899 void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
4900{
4901 TCGv_i64 dst, src0, src1, src2;
4902
4903 if (gen_trap_ifnofpu(dc)) {
4904 return true;
4905 }
4906
4907 dst = gen_dest_fpr_D(dc, a->rd);
4908 src0 = gen_load_fpr_D(dc, a->rd);
4909 src1 = gen_load_fpr_D(dc, a->rs1);
4910 src2 = gen_load_fpr_D(dc, a->rs2);
4911 func(dst, src0, src1, src2);
4912 gen_store_fpr_D(dc, a->rd, dst);
4913 return advance_pc(dc);
4914}
4915
4916TRANS(PDIST, VIS1, do_dddd, a, gen_helper_pdist)
4917
a4056239
RH
4918static bool do_env_qqq(DisasContext *dc, arg_r_r_r *a,
4919 void (*func)(TCGv_env))
4920{
4921 if (gen_trap_ifnofpu(dc)) {
4922 return true;
4923 }
4924 if (gen_trap_float128(dc)) {
4925 return true;
4926 }
4927
4928 gen_op_clear_ieee_excp_and_FTT();
4929 gen_op_load_fpr_QT0(QFPREG(a->rs1));
4930 gen_op_load_fpr_QT1(QFPREG(a->rs2));
4931 func(tcg_env);
4932 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4933 gen_op_store_QT0_fpr(QFPREG(a->rd));
4934 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4935 return advance_pc(dc);
4936}
4937
4938TRANS(FADDq, ALL, do_env_qqq, a, gen_helper_faddq)
4939TRANS(FSUBq, ALL, do_env_qqq, a, gen_helper_fsubq)
4940TRANS(FMULq, ALL, do_env_qqq, a, gen_helper_fmulq)
4941TRANS(FDIVq, ALL, do_env_qqq, a, gen_helper_fdivq)
4942
5e3b17bb
RH
4943static bool trans_FdMULq(DisasContext *dc, arg_r_r_r *a)
4944{
4945 TCGv_i64 src1, src2;
4946
4947 if (gen_trap_ifnofpu(dc)) {
4948 return true;
4949 }
4950 if (gen_trap_float128(dc)) {
4951 return true;
4952 }
4953
4954 gen_op_clear_ieee_excp_and_FTT();
4955 src1 = gen_load_fpr_D(dc, a->rs1);
4956 src2 = gen_load_fpr_D(dc, a->rs2);
4957 gen_helper_fdmulq(tcg_env, src1, src2);
4958 gen_helper_check_ieee_exceptions(cpu_fsr, tcg_env);
4959 gen_op_store_QT0_fpr(QFPREG(a->rd));
4960 gen_update_fprs_dirty(dc, QFPREG(a->rd));
4961 return advance_pc(dc);
4962}
4963
f7ec8155
RH
4964static bool do_fmovr(DisasContext *dc, arg_FMOVRs *a, bool is_128,
4965 void (*func)(DisasContext *, DisasCompare *, int, int))
4966{
4967 DisasCompare cmp;
4968
4969 if (gen_trap_ifnofpu(dc)) {
4970 return true;
4971 }
4972 if (is_128 && gen_trap_float128(dc)) {
4973 return true;
4974 }
4975
4976 gen_op_clear_ieee_excp_and_FTT();
4977 gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
4978 func(dc, &cmp, a->rd, a->rs2);
4979 return advance_pc(dc);
4980}
4981
4982TRANS(FMOVRs, 64, do_fmovr, a, false, gen_fmovs)
4983TRANS(FMOVRd, 64, do_fmovr, a, false, gen_fmovd)
4984TRANS(FMOVRq, 64, do_fmovr, a, true, gen_fmovq)
4985
4986static bool do_fmovcc(DisasContext *dc, arg_FMOVscc *a, bool is_128,
4987 void (*func)(DisasContext *, DisasCompare *, int, int))
4988{
4989 DisasCompare cmp;
4990
4991 if (gen_trap_ifnofpu(dc)) {
4992 return true;
4993 }
4994 if (is_128 && gen_trap_float128(dc)) {
4995 return true;
4996 }
4997
4998 gen_op_clear_ieee_excp_and_FTT();
4999 gen_compare(&cmp, a->cc, a->cond, dc);
5000 func(dc, &cmp, a->rd, a->rs2);
5001 return advance_pc(dc);
5002}
5003
5004TRANS(FMOVscc, 64, do_fmovcc, a, false, gen_fmovs)
5005TRANS(FMOVdcc, 64, do_fmovcc, a, false, gen_fmovd)
5006TRANS(FMOVqcc, 64, do_fmovcc, a, true, gen_fmovq)
5007
5008static bool do_fmovfcc(DisasContext *dc, arg_FMOVsfcc *a, bool is_128,
5009 void (*func)(DisasContext *, DisasCompare *, int, int))
5010{
5011 DisasCompare cmp;
5012
5013 if (gen_trap_ifnofpu(dc)) {
5014 return true;
5015 }
5016 if (is_128 && gen_trap_float128(dc)) {
5017 return true;
5018 }
5019
5020 gen_op_clear_ieee_excp_and_FTT();
5021 gen_fcompare(&cmp, a->cc, a->cond);
5022 func(dc, &cmp, a->rd, a->rs2);
5023 return advance_pc(dc);
5024}
5025
5026TRANS(FMOVsfcc, 64, do_fmovfcc, a, false, gen_fmovs)
5027TRANS(FMOVdfcc, 64, do_fmovfcc, a, false, gen_fmovd)
5028TRANS(FMOVqfcc, 64, do_fmovfcc, a, true, gen_fmovq)
5029
40f9ad21
RH
5030static bool do_fcmps(DisasContext *dc, arg_FCMPs *a, bool e)
5031{
5032 TCGv_i32 src1, src2;
5033
5034 if (avail_32(dc) && a->cc != 0) {
5035 return false;
5036 }
5037 if (gen_trap_ifnofpu(dc)) {
5038 return true;
5039 }
5040
5041 gen_op_clear_ieee_excp_and_FTT();
5042 src1 = gen_load_fpr_F(dc, a->rs1);
5043 src2 = gen_load_fpr_F(dc, a->rs2);
5044 if (e) {
5045 gen_op_fcmpes(a->cc, src1, src2);
5046 } else {
5047 gen_op_fcmps(a->cc, src1, src2);
5048 }
5049 return advance_pc(dc);
5050}
5051
5052TRANS(FCMPs, ALL, do_fcmps, a, false)
5053TRANS(FCMPEs, ALL, do_fcmps, a, true)
5054
5055static bool do_fcmpd(DisasContext *dc, arg_FCMPd *a, bool e)
5056{
5057 TCGv_i64 src1, src2;
5058
5059 if (avail_32(dc) && a->cc != 0) {
5060 return false;
5061 }
5062 if (gen_trap_ifnofpu(dc)) {
5063 return true;
5064 }
5065
5066 gen_op_clear_ieee_excp_and_FTT();
5067 src1 = gen_load_fpr_D(dc, a->rs1);
5068 src2 = gen_load_fpr_D(dc, a->rs2);
5069 if (e) {
5070 gen_op_fcmped(a->cc, src1, src2);
5071 } else {
5072 gen_op_fcmpd(a->cc, src1, src2);
5073 }
5074 return advance_pc(dc);
5075}
5076
5077TRANS(FCMPd, ALL, do_fcmpd, a, false)
5078TRANS(FCMPEd, ALL, do_fcmpd, a, true)
5079
5080static bool do_fcmpq(DisasContext *dc, arg_FCMPq *a, bool e)
5081{
5082 if (avail_32(dc) && a->cc != 0) {
5083 return false;
5084 }
5085 if (gen_trap_ifnofpu(dc)) {
5086 return true;
5087 }
5088 if (gen_trap_float128(dc)) {
5089 return true;
5090 }
5091
5092 gen_op_clear_ieee_excp_and_FTT();
5093 gen_op_load_fpr_QT0(QFPREG(a->rs1));
5094 gen_op_load_fpr_QT1(QFPREG(a->rs2));
5095 if (e) {
5096 gen_op_fcmpeq(a->cc);
5097 } else {
5098 gen_op_fcmpq(a->cc);
5099 }
5100 return advance_pc(dc);
5101}
5102
5103TRANS(FCMPq, ALL, do_fcmpq, a, false)
5104TRANS(FCMPEq, ALL, do_fcmpq, a, true)
5105
6e61bc94 5106static void sparc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
7a3f1944 5107{
6e61bc94 5108 DisasContext *dc = container_of(dcbase, DisasContext, base);
b77af26e 5109 CPUSPARCState *env = cpu_env(cs);
6e61bc94 5110 int bound;
af00be49
EC
5111
5112 dc->pc = dc->base.pc_first;
6e61bc94 5113 dc->npc = (target_ulong)dc->base.tb->cs_base;
6e61bc94 5114 dc->mem_idx = dc->base.tb->flags & TB_FLAG_MMU_MASK;
576e1c4c 5115 dc->def = &env->def;
6e61bc94
EC
5116 dc->fpu_enabled = tb_fpu_enabled(dc->base.tb->flags);
5117 dc->address_mask_32bit = tb_am_enabled(dc->base.tb->flags);
c9b459aa 5118#ifndef CONFIG_USER_ONLY
6e61bc94 5119 dc->supervisor = (dc->base.tb->flags & TB_FLAG_SUPER) != 0;
c9b459aa 5120#endif
a6d567e5 5121#ifdef TARGET_SPARC64
f9c816c0 5122 dc->fprs_dirty = 0;
6e61bc94 5123 dc->asi = (dc->base.tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff;
c9b459aa 5124#ifndef CONFIG_USER_ONLY
6e61bc94 5125 dc->hypervisor = (dc->base.tb->flags & TB_FLAG_HYPER) != 0;
c9b459aa 5126#endif
a6d567e5 5127#endif
6e61bc94
EC
5128 /*
5129 * if we reach a page boundary, we stop generation so that the
5130 * PC of a TT_TFAULT exception is always in the right page
5131 */
5132 bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
5133 dc->base.max_insns = MIN(dc->base.max_insns, bound);
5134}
cf495bcf 5135
6e61bc94
EC
5136static void sparc_tr_tb_start(DisasContextBase *db, CPUState *cs)
5137{
5138}
190ce7fb 5139
6e61bc94
EC
5140static void sparc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
5141{
5142 DisasContext *dc = container_of(dcbase, DisasContext, base);
633c4283 5143 target_ulong npc = dc->npc;
667b8e29 5144
633c4283
RH
5145 if (npc & 3) {
5146 switch (npc) {
5147 case JUMP_PC:
5148 assert(dc->jump_pc[1] == dc->pc + 4);
5149 npc = dc->jump_pc[0] | JUMP_PC;
5150 break;
5151 case DYNAMIC_PC:
5152 case DYNAMIC_PC_LOOKUP:
5153 npc = DYNAMIC_PC;
5154 break;
5155 default:
5156 g_assert_not_reached();
5157 }
6e61bc94 5158 }
633c4283 5159 tcg_gen_insn_start(dc->pc, npc);
6e61bc94 5160}
b933066a 5161
6e61bc94
EC
5162static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
5163{
5164 DisasContext *dc = container_of(dcbase, DisasContext, base);
b77af26e 5165 CPUSPARCState *env = cpu_env(cs);
6e61bc94 5166 unsigned int insn;
0f8a249a 5167
4e116893 5168 insn = translator_ldl(env, &dc->base, dc->pc);
6e61bc94 5169 dc->base.pc_next += 4;
878cc677
RH
5170
5171 if (!decode(dc, insn)) {
ba9c09b4 5172 gen_exception(dc, TT_ILL_INSN);
878cc677 5173 }
e80cfcfc 5174
6e61bc94
EC
5175 if (dc->base.is_jmp == DISAS_NORETURN) {
5176 return;
5177 }
5178 if (dc->pc != dc->base.pc_next) {
5179 dc->base.is_jmp = DISAS_TOO_MANY;
b09b2fd3 5180 }
6e61bc94
EC
5181}
5182
5183static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
5184{
5185 DisasContext *dc = container_of(dcbase, DisasContext, base);
186e7890 5186 DisasDelayException *e, *e_next;
633c4283 5187 bool may_lookup;
6e61bc94 5188
89527e3a
RH
5189 finishing_insn(dc);
5190
46bb0137
MCA
5191 switch (dc->base.is_jmp) {
5192 case DISAS_NEXT:
5193 case DISAS_TOO_MANY:
633c4283 5194 if (((dc->pc | dc->npc) & 3) == 0) {
72cbca10 5195 /* static PC and NPC: we can use direct chaining */
2f5680ee 5196 gen_goto_tb(dc, 0, dc->pc, dc->npc);
633c4283
RH
5197 break;
5198 }
5199
930f1865 5200 may_lookup = true;
633c4283
RH
5201 if (dc->pc & 3) {
5202 switch (dc->pc) {
5203 case DYNAMIC_PC_LOOKUP:
633c4283
RH
5204 break;
5205 case DYNAMIC_PC:
5206 may_lookup = false;
5207 break;
5208 default:
5209 g_assert_not_reached();
b09b2fd3 5210 }
633c4283
RH
5211 } else {
5212 tcg_gen_movi_tl(cpu_pc, dc->pc);
633c4283
RH
5213 }
5214
930f1865
RH
5215 if (dc->npc & 3) {
5216 switch (dc->npc) {
5217 case JUMP_PC:
5218 gen_generic_branch(dc);
5219 break;
5220 case DYNAMIC_PC:
5221 may_lookup = false;
5222 break;
5223 case DYNAMIC_PC_LOOKUP:
5224 break;
5225 default:
5226 g_assert_not_reached();
5227 }
5228 } else {
5229 tcg_gen_movi_tl(cpu_npc, dc->npc);
5230 }
633c4283
RH
5231 if (may_lookup) {
5232 tcg_gen_lookup_and_goto_ptr();
5233 } else {
07ea28b4 5234 tcg_gen_exit_tb(NULL, 0);
72cbca10 5235 }
46bb0137
MCA
5236 break;
5237
5238 case DISAS_NORETURN:
5239 break;
5240
5241 case DISAS_EXIT:
5242 /* Exit TB */
5243 save_state(dc);
5244 tcg_gen_exit_tb(NULL, 0);
5245 break;
5246
5247 default:
5248 g_assert_not_reached();
72cbca10 5249 }
186e7890
RH
5250
5251 for (e = dc->delay_excp_list; e ; e = e_next) {
5252 gen_set_label(e->lab);
5253
5254 tcg_gen_movi_tl(cpu_pc, e->pc);
5255 if (e->npc % 4 == 0) {
5256 tcg_gen_movi_tl(cpu_npc, e->npc);
5257 }
5258 gen_helper_raise_exception(tcg_env, e->excp);
5259
5260 e_next = e->next;
5261 g_free(e);
5262 }
6e61bc94
EC
5263}
5264
8eb806a7
RH
5265static void sparc_tr_disas_log(const DisasContextBase *dcbase,
5266 CPUState *cpu, FILE *logfile)
6e61bc94 5267{
8eb806a7
RH
5268 fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
5269 target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
6e61bc94
EC
5270}
5271
5272static const TranslatorOps sparc_tr_ops = {
5273 .init_disas_context = sparc_tr_init_disas_context,
5274 .tb_start = sparc_tr_tb_start,
5275 .insn_start = sparc_tr_insn_start,
6e61bc94
EC
5276 .translate_insn = sparc_tr_translate_insn,
5277 .tb_stop = sparc_tr_tb_stop,
5278 .disas_log = sparc_tr_disas_log,
5279};
5280
597f9b2d 5281void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
306c8721 5282 target_ulong pc, void *host_pc)
6e61bc94
EC
5283{
5284 DisasContext dc = {};
5285
306c8721 5286 translator_loop(cs, tb, max_insns, pc, host_pc, &sparc_tr_ops, &dc.base);
7a3f1944
FB
5287}
5288
55c3ceef 5289void sparc_tcg_init(void)
e80cfcfc 5290{
d2dc4069 5291 static const char gregnames[32][4] = {
0ea63844 5292 "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
d2dc4069
RH
5293 "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7",
5294 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
5295 "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7",
f5069b26 5296 };
0ea63844 5297 static const char fregnames[32][4] = {
30038fd8
RH
5298 "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14",
5299 "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30",
5300 "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",
5301 "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
714547bb 5302 };
aaed909a 5303
0ea63844
RH
5304 static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
5305#ifdef TARGET_SPARC64
5306 { &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" },
2a1905c7
RH
5307 { &cpu_xcc_Z, offsetof(CPUSPARCState, xcc_Z), "xcc_Z" },
5308 { &cpu_xcc_C, offsetof(CPUSPARCState, xcc_C), "xcc_C" },
1a2fb1c0 5309#endif
2a1905c7
RH
5310 { &cpu_cc_N, offsetof(CPUSPARCState, cc_N), "cc_N" },
5311 { &cpu_cc_V, offsetof(CPUSPARCState, cc_V), "cc_V" },
5312 { &cpu_icc_Z, offsetof(CPUSPARCState, icc_Z), "icc_Z" },
5313 { &cpu_icc_C, offsetof(CPUSPARCState, icc_C), "icc_C" },
0ea63844 5314 { &cpu_cond, offsetof(CPUSPARCState, cond), "cond" },
0ea63844
RH
5315 { &cpu_fsr, offsetof(CPUSPARCState, fsr), "fsr" },
5316 { &cpu_pc, offsetof(CPUSPARCState, pc), "pc" },
5317 { &cpu_npc, offsetof(CPUSPARCState, npc), "npc" },
5318 { &cpu_y, offsetof(CPUSPARCState, y), "y" },
0ea63844 5319 { &cpu_tbr, offsetof(CPUSPARCState, tbr), "tbr" },
0ea63844
RH
5320 };
5321
5322 unsigned int i;
5323
ad75a51e 5324 cpu_regwptr = tcg_global_mem_new_ptr(tcg_env,
0ea63844
RH
5325 offsetof(CPUSPARCState, regwptr),
5326 "regwptr");
5327
0ea63844 5328 for (i = 0; i < ARRAY_SIZE(rtl); ++i) {
ad75a51e 5329 *rtl[i].ptr = tcg_global_mem_new(tcg_env, rtl[i].off, rtl[i].name);
0ea63844
RH
5330 }
5331
f764718d 5332 cpu_regs[0] = NULL;
0ea63844 5333 for (i = 1; i < 8; ++i) {
ad75a51e 5334 cpu_regs[i] = tcg_global_mem_new(tcg_env,
d2dc4069
RH
5335 offsetof(CPUSPARCState, gregs[i]),
5336 gregnames[i]);
5337 }
5338
5339 for (i = 8; i < 32; ++i) {
5340 cpu_regs[i] = tcg_global_mem_new(cpu_regwptr,
5341 (i - 8) * sizeof(target_ulong),
5342 gregnames[i]);
0ea63844
RH
5343 }
5344
5345 for (i = 0; i < TARGET_DPREGS; i++) {
ad75a51e 5346 cpu_fpr[i] = tcg_global_mem_new_i64(tcg_env,
0ea63844
RH
5347 offsetof(CPUSPARCState, fpr[i]),
5348 fregnames[i]);
1a2fb1c0 5349 }
b597eedc
RH
5350
5351#ifdef TARGET_SPARC64
5352 cpu_fprs = tcg_global_mem_new_i32(tcg_env,
5353 offsetof(CPUSPARCState, fprs), "fprs");
5354#endif
658138bc 5355}
d2856f1a 5356
f36aaa53
RH
5357void sparc_restore_state_to_opc(CPUState *cs,
5358 const TranslationBlock *tb,
5359 const uint64_t *data)
d2856f1a 5360{
f36aaa53
RH
5361 SPARCCPU *cpu = SPARC_CPU(cs);
5362 CPUSPARCState *env = &cpu->env;
bad729e2
RH
5363 target_ulong pc = data[0];
5364 target_ulong npc = data[1];
5365
5366 env->pc = pc;
6c42444f 5367 if (npc == DYNAMIC_PC) {
d2856f1a 5368 /* dynamic NPC: already stored */
6c42444f 5369 } else if (npc & JUMP_PC) {
d7da2a10
BS
5370 /* jump PC: use 'cond' and the jump targets of the translation */
5371 if (env->cond) {
6c42444f 5372 env->npc = npc & ~3;
d7da2a10 5373 } else {
6c42444f 5374 env->npc = pc + 4;
d7da2a10 5375 }
d2856f1a
AJ
5376 } else {
5377 env->npc = npc;
5378 }
5379}