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