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