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