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