blob: 39af3af05f1520563bb8616b0cf3030b7f7c8451 [file] [log] [blame]
Guan Xuetao6e64da32011-04-12 16:25:59 +08001/*
2 * UniCore32 translation
3 *
Guan Xuetao527d9972012-08-10 14:42:22 +08004 * Copyright (C) 2010-2012 Guan Xuetao
Guan Xuetao6e64da32011-04-12 16:25:59 +08005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
Andreas Färber2b3bc6c2012-03-13 16:48:19 +01008 * published by the Free Software Foundation, or (at your option) any
9 * later version. See the COPYING file in the top-level directory.
Guan Xuetao6e64da32011-04-12 16:25:59 +080010 */
Peter Maydell5af98cc2016-01-26 18:17:01 +000011#include "qemu/osdep.h"
Guan Xuetao6e64da32011-04-12 16:25:59 +080012
13#include "cpu.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +020014#include "disas/disas.h"
Guan Xuetao6e64da32011-04-12 16:25:59 +080015#include "tcg-op.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010016#include "qemu/log.h"
Paolo Bonzinif08b6172014-03-28 19:42:10 +010017#include "exec/cpu_ldst.h"
Guan Xuetao6e64da32011-04-12 16:25:59 +080018
Richard Henderson2ef61752014-04-07 22:31:41 -070019#include "exec/helper-proto.h"
20#include "exec/helper-gen.h"
Guan Xuetao6e64da32011-04-12 16:25:59 +080021
Lluís Vilanovaa7e30d82014-05-30 14:12:25 +020022#include "trace-tcg.h"
Paolo Bonzini508127e2016-01-07 16:55:28 +030023#include "exec/log.h"
Lluís Vilanovaa7e30d82014-05-30 14:12:25 +020024
25
Guan Xuetao6e64da32011-04-12 16:25:59 +080026/* internal defines */
27typedef struct DisasContext {
28 target_ulong pc;
29 int is_jmp;
30 /* Nonzero if this instruction has been conditionally skipped. */
31 int condjmp;
32 /* The label that will be jumped to when the instruction is skipped. */
Richard Henderson42a268c2015-02-13 12:51:55 -080033 TCGLabel *condlabel;
Guan Xuetao6e64da32011-04-12 16:25:59 +080034 struct TranslationBlock *tb;
35 int singlestep_enabled;
Guan Xuetaoef031682012-08-10 14:42:26 +080036#ifndef CONFIG_USER_ONLY
37 int user;
38#endif
Guan Xuetao6e64da32011-04-12 16:25:59 +080039} DisasContext;
40
Guan Xuetaoef031682012-08-10 14:42:26 +080041#ifndef CONFIG_USER_ONLY
42#define IS_USER(s) (s->user)
43#else
44#define IS_USER(s) 1
45#endif
Guan Xuetao6e64da32011-04-12 16:25:59 +080046
47/* These instructions trap after executing, so defer them until after the
48 conditional executions state has been updated. */
49#define DISAS_SYSCALL 5
50
Lluís Vilanova1bcea732016-02-25 17:43:15 +010051static TCGv_env cpu_env;
Guan Xuetao6e64da32011-04-12 16:25:59 +080052static TCGv_i32 cpu_R[32];
53
54/* FIXME: These should be removed. */
55static TCGv cpu_F0s, cpu_F1s;
56static TCGv_i64 cpu_F0d, cpu_F1d;
57
Paolo Bonzini022c62c2012-12-17 18:19:49 +010058#include "exec/gen-icount.h"
Guan Xuetao6e64da32011-04-12 16:25:59 +080059
60static const char *regnames[] = {
61 "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07",
62 "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15",
63 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
64 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "pc" };
65
66/* initialize TCG globals. */
67void uc32_translate_init(void)
68{
69 int i;
70
71 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
72
73 for (i = 0; i < 32; i++) {
Richard Hendersone1ccc052013-09-18 12:53:09 -070074 cpu_R[i] = tcg_global_mem_new_i32(cpu_env,
Andreas Färbereb23b552012-03-14 01:38:23 +010075 offsetof(CPUUniCore32State, regs[i]), regnames[i]);
Guan Xuetao6e64da32011-04-12 16:25:59 +080076 }
Guan Xuetao6e64da32011-04-12 16:25:59 +080077}
78
79static int num_temps;
80
81/* Allocate a temporary variable. */
82static TCGv_i32 new_tmp(void)
83{
84 num_temps++;
85 return tcg_temp_new_i32();
86}
87
88/* Release a temporary variable. */
89static void dead_tmp(TCGv tmp)
90{
91 tcg_temp_free(tmp);
92 num_temps--;
93}
94
95static inline TCGv load_cpu_offset(int offset)
96{
97 TCGv tmp = new_tmp();
98 tcg_gen_ld_i32(tmp, cpu_env, offset);
99 return tmp;
100}
101
Andreas Färbereb23b552012-03-14 01:38:23 +0100102#define load_cpu_field(name) load_cpu_offset(offsetof(CPUUniCore32State, name))
Guan Xuetao6e64da32011-04-12 16:25:59 +0800103
104static inline void store_cpu_offset(TCGv var, int offset)
105{
106 tcg_gen_st_i32(var, cpu_env, offset);
107 dead_tmp(var);
108}
109
110#define store_cpu_field(var, name) \
Andreas Färbereb23b552012-03-14 01:38:23 +0100111 store_cpu_offset(var, offsetof(CPUUniCore32State, name))
Guan Xuetao6e64da32011-04-12 16:25:59 +0800112
113/* Set a variable to the value of a CPU register. */
114static void load_reg_var(DisasContext *s, TCGv var, int reg)
115{
116 if (reg == 31) {
117 uint32_t addr;
118 /* normaly, since we updated PC */
119 addr = (long)s->pc;
120 tcg_gen_movi_i32(var, addr);
121 } else {
122 tcg_gen_mov_i32(var, cpu_R[reg]);
123 }
124}
125
126/* Create a new temporary and set it to the value of a CPU register. */
127static inline TCGv load_reg(DisasContext *s, int reg)
128{
129 TCGv tmp = new_tmp();
130 load_reg_var(s, tmp, reg);
131 return tmp;
132}
133
134/* Set a CPU register. The source must be a temporary and will be
135 marked as dead. */
136static void store_reg(DisasContext *s, int reg, TCGv var)
137{
138 if (reg == 31) {
139 tcg_gen_andi_i32(var, var, ~3);
140 s->is_jmp = DISAS_JUMP;
141 }
142 tcg_gen_mov_i32(cpu_R[reg], var);
143 dead_tmp(var);
144}
145
146/* Value extensions. */
147#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
148#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
149#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
150#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
151
152#define UCOP_REG_M (((insn) >> 0) & 0x1f)
153#define UCOP_REG_N (((insn) >> 19) & 0x1f)
154#define UCOP_REG_D (((insn) >> 14) & 0x1f)
155#define UCOP_REG_S (((insn) >> 9) & 0x1f)
156#define UCOP_REG_LO (((insn) >> 14) & 0x1f)
157#define UCOP_REG_HI (((insn) >> 9) & 0x1f)
158#define UCOP_SH_OP (((insn) >> 6) & 0x03)
159#define UCOP_SH_IM (((insn) >> 9) & 0x1f)
160#define UCOP_OPCODES (((insn) >> 25) & 0x0f)
161#define UCOP_IMM_9 (((insn) >> 0) & 0x1ff)
162#define UCOP_IMM10 (((insn) >> 0) & 0x3ff)
163#define UCOP_IMM14 (((insn) >> 0) & 0x3fff)
164#define UCOP_COND (((insn) >> 25) & 0x0f)
165#define UCOP_CMOV_COND (((insn) >> 19) & 0x0f)
166#define UCOP_CPNUM (((insn) >> 10) & 0x0f)
167#define UCOP_UCF64_FMT (((insn) >> 24) & 0x03)
168#define UCOP_UCF64_FUNC (((insn) >> 6) & 0x0f)
169#define UCOP_UCF64_COND (((insn) >> 6) & 0x0f)
170
171#define UCOP_SET(i) ((insn) & (1 << (i)))
172#define UCOP_SET_P UCOP_SET(28)
173#define UCOP_SET_U UCOP_SET(27)
174#define UCOP_SET_B UCOP_SET(26)
175#define UCOP_SET_W UCOP_SET(25)
176#define UCOP_SET_L UCOP_SET(24)
177#define UCOP_SET_S UCOP_SET(24)
178
Andreas Färbera47dddd2013-09-03 17:38:47 +0200179#define ILLEGAL cpu_abort(CPU(cpu), \
Guan Xuetao6e64da32011-04-12 16:25:59 +0800180 "Illegal UniCore32 instruction %x at line %d!", \
181 insn, __LINE__)
182
Guan Xuetao527d9972012-08-10 14:42:22 +0800183#ifndef CONFIG_USER_ONLY
184static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s,
185 uint32_t insn)
186{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200187 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao527d9972012-08-10 14:42:22 +0800188 TCGv tmp, tmp2, tmp3;
189 if ((insn & 0xfe000000) == 0xe0000000) {
190 tmp2 = new_tmp();
191 tmp3 = new_tmp();
192 tcg_gen_movi_i32(tmp2, UCOP_REG_N);
193 tcg_gen_movi_i32(tmp3, UCOP_IMM10);
194 if (UCOP_SET_L) {
195 tmp = new_tmp();
196 gen_helper_cp0_get(tmp, cpu_env, tmp2, tmp3);
197 store_reg(s, UCOP_REG_D, tmp);
198 } else {
199 tmp = load_reg(s, UCOP_REG_D);
200 gen_helper_cp0_set(cpu_env, tmp, tmp2, tmp3);
201 dead_tmp(tmp);
202 }
203 dead_tmp(tmp2);
204 dead_tmp(tmp3);
205 return;
206 }
207 ILLEGAL;
208}
209
210static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s,
211 uint32_t insn)
212{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200213 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao527d9972012-08-10 14:42:22 +0800214 TCGv tmp;
215
216 if ((insn & 0xff003fff) == 0xe1000400) {
217 /*
218 * movc rd, pp.nn, #imm9
219 * rd: UCOP_REG_D
220 * nn: UCOP_REG_N (must be 0)
221 * imm9: 0
222 */
223 if (UCOP_REG_N == 0) {
224 tmp = new_tmp();
225 tcg_gen_movi_i32(tmp, 0);
226 store_reg(s, UCOP_REG_D, tmp);
227 return;
228 } else {
229 ILLEGAL;
230 }
231 }
232 if ((insn & 0xff003fff) == 0xe0000401) {
233 /*
234 * movc pp.nn, rn, #imm9
235 * rn: UCOP_REG_D
236 * nn: UCOP_REG_N (must be 1)
237 * imm9: 1
238 */
239 if (UCOP_REG_N == 1) {
240 tmp = load_reg(s, UCOP_REG_D);
241 gen_helper_cp1_putc(tmp);
242 dead_tmp(tmp);
243 return;
244 } else {
245 ILLEGAL;
246 }
247 }
248 ILLEGAL;
249}
250#endif
251
Guan Xuetao6e64da32011-04-12 16:25:59 +0800252static inline void gen_set_asr(TCGv var, uint32_t mask)
253{
254 TCGv tmp_mask = tcg_const_i32(mask);
Blue Swirl04a130e2012-09-02 07:42:33 +0000255 gen_helper_asr_write(cpu_env, var, tmp_mask);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800256 tcg_temp_free_i32(tmp_mask);
257}
258/* Set NZCV flags from the high 4 bits of var. */
259#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV)
260
261static void gen_exception(int excp)
262{
263 TCGv tmp = new_tmp();
264 tcg_gen_movi_i32(tmp, excp);
Blue Swirl04a130e2012-09-02 07:42:33 +0000265 gen_helper_exception(cpu_env, tmp);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800266 dead_tmp(tmp);
267}
268
Andreas Färbereb23b552012-03-14 01:38:23 +0100269#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, CF))
Guan Xuetao6e64da32011-04-12 16:25:59 +0800270
271/* Set CF to the top bit of var. */
272static void gen_set_CF_bit31(TCGv var)
273{
274 TCGv tmp = new_tmp();
275 tcg_gen_shri_i32(tmp, var, 31);
276 gen_set_CF(tmp);
277 dead_tmp(tmp);
278}
279
280/* Set N and Z flags from var. */
281static inline void gen_logic_CC(TCGv var)
282{
Andreas Färbereb23b552012-03-14 01:38:23 +0100283 tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, NF));
284 tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, ZF));
Guan Xuetao6e64da32011-04-12 16:25:59 +0800285}
286
287/* dest = T0 + T1 + CF. */
288static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
289{
290 TCGv tmp;
291 tcg_gen_add_i32(dest, t0, t1);
292 tmp = load_cpu_field(CF);
293 tcg_gen_add_i32(dest, dest, tmp);
294 dead_tmp(tmp);
295}
296
297/* dest = T0 - T1 + CF - 1. */
298static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
299{
300 TCGv tmp;
301 tcg_gen_sub_i32(dest, t0, t1);
302 tmp = load_cpu_field(CF);
303 tcg_gen_add_i32(dest, dest, tmp);
304 tcg_gen_subi_i32(dest, dest, 1);
305 dead_tmp(tmp);
306}
307
308static void shifter_out_im(TCGv var, int shift)
309{
310 TCGv tmp = new_tmp();
311 if (shift == 0) {
312 tcg_gen_andi_i32(tmp, var, 1);
313 } else {
314 tcg_gen_shri_i32(tmp, var, shift);
315 if (shift != 31) {
316 tcg_gen_andi_i32(tmp, tmp, 1);
317 }
318 }
319 gen_set_CF(tmp);
320 dead_tmp(tmp);
321}
322
323/* Shift by immediate. Includes special handling for shift == 0. */
324static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift,
325 int flags)
326{
327 switch (shiftop) {
328 case 0: /* LSL */
329 if (shift != 0) {
330 if (flags) {
331 shifter_out_im(var, 32 - shift);
332 }
333 tcg_gen_shli_i32(var, var, shift);
334 }
335 break;
336 case 1: /* LSR */
337 if (shift == 0) {
338 if (flags) {
339 tcg_gen_shri_i32(var, var, 31);
340 gen_set_CF(var);
341 }
342 tcg_gen_movi_i32(var, 0);
343 } else {
344 if (flags) {
345 shifter_out_im(var, shift - 1);
346 }
347 tcg_gen_shri_i32(var, var, shift);
348 }
349 break;
350 case 2: /* ASR */
351 if (shift == 0) {
352 shift = 32;
353 }
354 if (flags) {
355 shifter_out_im(var, shift - 1);
356 }
357 if (shift == 32) {
358 shift = 31;
359 }
360 tcg_gen_sari_i32(var, var, shift);
361 break;
362 case 3: /* ROR/RRX */
363 if (shift != 0) {
364 if (flags) {
365 shifter_out_im(var, shift - 1);
366 }
367 tcg_gen_rotri_i32(var, var, shift); break;
368 } else {
369 TCGv tmp = load_cpu_field(CF);
370 if (flags) {
371 shifter_out_im(var, 0);
372 }
373 tcg_gen_shri_i32(var, var, 1);
374 tcg_gen_shli_i32(tmp, tmp, 31);
375 tcg_gen_or_i32(var, var, tmp);
376 dead_tmp(tmp);
377 }
378 }
379};
380
381static inline void gen_uc32_shift_reg(TCGv var, int shiftop,
382 TCGv shift, int flags)
383{
384 if (flags) {
385 switch (shiftop) {
386 case 0:
Blue Swirl04a130e2012-09-02 07:42:33 +0000387 gen_helper_shl_cc(var, cpu_env, var, shift);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800388 break;
389 case 1:
Blue Swirl04a130e2012-09-02 07:42:33 +0000390 gen_helper_shr_cc(var, cpu_env, var, shift);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800391 break;
392 case 2:
Blue Swirl04a130e2012-09-02 07:42:33 +0000393 gen_helper_sar_cc(var, cpu_env, var, shift);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800394 break;
395 case 3:
Blue Swirl04a130e2012-09-02 07:42:33 +0000396 gen_helper_ror_cc(var, cpu_env, var, shift);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800397 break;
398 }
399 } else {
400 switch (shiftop) {
401 case 0:
402 gen_helper_shl(var, var, shift);
403 break;
404 case 1:
405 gen_helper_shr(var, var, shift);
406 break;
407 case 2:
408 gen_helper_sar(var, var, shift);
409 break;
410 case 3:
411 tcg_gen_andi_i32(shift, shift, 0x1f);
412 tcg_gen_rotr_i32(var, var, shift);
413 break;
414 }
415 }
416 dead_tmp(shift);
417}
418
Richard Henderson42a268c2015-02-13 12:51:55 -0800419static void gen_test_cc(int cc, TCGLabel *label)
Guan Xuetao6e64da32011-04-12 16:25:59 +0800420{
421 TCGv tmp;
422 TCGv tmp2;
Richard Henderson42a268c2015-02-13 12:51:55 -0800423 TCGLabel *inv;
Guan Xuetao6e64da32011-04-12 16:25:59 +0800424
425 switch (cc) {
426 case 0: /* eq: Z */
427 tmp = load_cpu_field(ZF);
428 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
429 break;
430 case 1: /* ne: !Z */
431 tmp = load_cpu_field(ZF);
432 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
433 break;
434 case 2: /* cs: C */
435 tmp = load_cpu_field(CF);
436 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
437 break;
438 case 3: /* cc: !C */
439 tmp = load_cpu_field(CF);
440 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
441 break;
442 case 4: /* mi: N */
443 tmp = load_cpu_field(NF);
444 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
445 break;
446 case 5: /* pl: !N */
447 tmp = load_cpu_field(NF);
448 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
449 break;
450 case 6: /* vs: V */
451 tmp = load_cpu_field(VF);
452 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
453 break;
454 case 7: /* vc: !V */
455 tmp = load_cpu_field(VF);
456 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
457 break;
458 case 8: /* hi: C && !Z */
459 inv = gen_new_label();
460 tmp = load_cpu_field(CF);
461 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
462 dead_tmp(tmp);
463 tmp = load_cpu_field(ZF);
464 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
465 gen_set_label(inv);
466 break;
467 case 9: /* ls: !C || Z */
468 tmp = load_cpu_field(CF);
469 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
470 dead_tmp(tmp);
471 tmp = load_cpu_field(ZF);
472 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
473 break;
474 case 10: /* ge: N == V -> N ^ V == 0 */
475 tmp = load_cpu_field(VF);
476 tmp2 = load_cpu_field(NF);
477 tcg_gen_xor_i32(tmp, tmp, tmp2);
478 dead_tmp(tmp2);
479 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
480 break;
481 case 11: /* lt: N != V -> N ^ V != 0 */
482 tmp = load_cpu_field(VF);
483 tmp2 = load_cpu_field(NF);
484 tcg_gen_xor_i32(tmp, tmp, tmp2);
485 dead_tmp(tmp2);
486 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
487 break;
488 case 12: /* gt: !Z && N == V */
489 inv = gen_new_label();
490 tmp = load_cpu_field(ZF);
491 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
492 dead_tmp(tmp);
493 tmp = load_cpu_field(VF);
494 tmp2 = load_cpu_field(NF);
495 tcg_gen_xor_i32(tmp, tmp, tmp2);
496 dead_tmp(tmp2);
497 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
498 gen_set_label(inv);
499 break;
500 case 13: /* le: Z || N != V */
501 tmp = load_cpu_field(ZF);
502 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
503 dead_tmp(tmp);
504 tmp = load_cpu_field(VF);
505 tmp2 = load_cpu_field(NF);
506 tcg_gen_xor_i32(tmp, tmp, tmp2);
507 dead_tmp(tmp2);
508 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
509 break;
510 default:
511 fprintf(stderr, "Bad condition code 0x%x\n", cc);
512 abort();
513 }
514 dead_tmp(tmp);
515}
516
517static const uint8_t table_logic_cc[16] = {
518 1, /* and */ 1, /* xor */ 0, /* sub */ 0, /* rsb */
519 0, /* add */ 0, /* adc */ 0, /* sbc */ 0, /* rsc */
520 1, /* andl */ 1, /* xorl */ 0, /* cmp */ 0, /* cmn */
521 1, /* orr */ 1, /* mov */ 1, /* bic */ 1, /* mvn */
522};
523
524/* Set PC state from an immediate address. */
525static inline void gen_bx_im(DisasContext *s, uint32_t addr)
526{
527 s->is_jmp = DISAS_UPDATE;
528 tcg_gen_movi_i32(cpu_R[31], addr & ~3);
529}
530
531/* Set PC state from var. var is marked as dead. */
532static inline void gen_bx(DisasContext *s, TCGv var)
533{
534 s->is_jmp = DISAS_UPDATE;
535 tcg_gen_andi_i32(cpu_R[31], var, ~3);
536 dead_tmp(var);
537}
538
539static inline void store_reg_bx(DisasContext *s, int reg, TCGv var)
540{
541 store_reg(s, reg, var);
542}
543
544static inline TCGv gen_ld8s(TCGv addr, int index)
545{
546 TCGv tmp = new_tmp();
547 tcg_gen_qemu_ld8s(tmp, addr, index);
548 return tmp;
549}
550
551static inline TCGv gen_ld8u(TCGv addr, int index)
552{
553 TCGv tmp = new_tmp();
554 tcg_gen_qemu_ld8u(tmp, addr, index);
555 return tmp;
556}
557
558static inline TCGv gen_ld16s(TCGv addr, int index)
559{
560 TCGv tmp = new_tmp();
561 tcg_gen_qemu_ld16s(tmp, addr, index);
562 return tmp;
563}
564
565static inline TCGv gen_ld16u(TCGv addr, int index)
566{
567 TCGv tmp = new_tmp();
568 tcg_gen_qemu_ld16u(tmp, addr, index);
569 return tmp;
570}
571
572static inline TCGv gen_ld32(TCGv addr, int index)
573{
574 TCGv tmp = new_tmp();
575 tcg_gen_qemu_ld32u(tmp, addr, index);
576 return tmp;
577}
578
Guan Xuetao6e64da32011-04-12 16:25:59 +0800579static inline void gen_st8(TCGv val, TCGv addr, int index)
580{
581 tcg_gen_qemu_st8(val, addr, index);
582 dead_tmp(val);
583}
584
585static inline void gen_st16(TCGv val, TCGv addr, int index)
586{
587 tcg_gen_qemu_st16(val, addr, index);
588 dead_tmp(val);
589}
590
591static inline void gen_st32(TCGv val, TCGv addr, int index)
592{
593 tcg_gen_qemu_st32(val, addr, index);
594 dead_tmp(val);
595}
596
Guan Xuetao6e64da32011-04-12 16:25:59 +0800597static inline void gen_set_pc_im(uint32_t val)
598{
599 tcg_gen_movi_i32(cpu_R[31], val);
600}
601
602/* Force a TB lookup after an instruction that changes the CPU state. */
603static inline void gen_lookup_tb(DisasContext *s)
604{
605 tcg_gen_movi_i32(cpu_R[31], s->pc & ~1);
606 s->is_jmp = DISAS_UPDATE;
607}
608
609static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
610 TCGv var)
611{
612 int val;
613 TCGv offset;
614
615 if (UCOP_SET(29)) {
616 /* immediate */
617 val = UCOP_IMM14;
618 if (!UCOP_SET_U) {
619 val = -val;
620 }
621 if (val != 0) {
622 tcg_gen_addi_i32(var, var, val);
623 }
624 } else {
625 /* shift/register */
626 offset = load_reg(s, UCOP_REG_M);
627 gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0);
628 if (!UCOP_SET_U) {
629 tcg_gen_sub_i32(var, var, offset);
630 } else {
631 tcg_gen_add_i32(var, var, offset);
632 }
633 dead_tmp(offset);
634 }
635}
636
637static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
638 TCGv var)
639{
640 int val;
641 TCGv offset;
642
643 if (UCOP_SET(26)) {
644 /* immediate */
645 val = (insn & 0x1f) | ((insn >> 4) & 0x3e0);
646 if (!UCOP_SET_U) {
647 val = -val;
648 }
649 if (val != 0) {
650 tcg_gen_addi_i32(var, var, val);
651 }
652 } else {
653 /* register */
654 offset = load_reg(s, UCOP_REG_M);
655 if (!UCOP_SET_U) {
656 tcg_gen_sub_i32(var, var, offset);
657 } else {
658 tcg_gen_add_i32(var, var, offset);
659 }
660 dead_tmp(offset);
661 }
662}
663
664static inline long ucf64_reg_offset(int reg)
665{
666 if (reg & 1) {
Andreas Färbereb23b552012-03-14 01:38:23 +0100667 return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1])
Guan Xuetao6e64da32011-04-12 16:25:59 +0800668 + offsetof(CPU_DoubleU, l.upper);
669 } else {
Andreas Färbereb23b552012-03-14 01:38:23 +0100670 return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1])
Guan Xuetao6e64da32011-04-12 16:25:59 +0800671 + offsetof(CPU_DoubleU, l.lower);
672 }
673}
674
675#define ucf64_gen_ld32(reg) load_cpu_offset(ucf64_reg_offset(reg))
676#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg))
677
678/* UniCore-F64 single load/store I_offset */
Andreas Färbereb23b552012-03-14 01:38:23 +0100679static void do_ucf64_ldst_i(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +0800680{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200681 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800682 int offset;
683 TCGv tmp;
684 TCGv addr;
685
686 addr = load_reg(s, UCOP_REG_N);
687 if (!UCOP_SET_P && !UCOP_SET_W) {
688 ILLEGAL;
689 }
690
691 if (UCOP_SET_P) {
692 offset = UCOP_IMM10 << 2;
693 if (!UCOP_SET_U) {
694 offset = -offset;
695 }
696 if (offset != 0) {
697 tcg_gen_addi_i32(addr, addr, offset);
698 }
699 }
700
701 if (UCOP_SET_L) { /* load */
702 tmp = gen_ld32(addr, IS_USER(s));
703 ucf64_gen_st32(tmp, UCOP_REG_D);
704 } else { /* store */
705 tmp = ucf64_gen_ld32(UCOP_REG_D);
706 gen_st32(tmp, addr, IS_USER(s));
707 }
708
709 if (!UCOP_SET_P) {
710 offset = UCOP_IMM10 << 2;
711 if (!UCOP_SET_U) {
712 offset = -offset;
713 }
714 if (offset != 0) {
715 tcg_gen_addi_i32(addr, addr, offset);
716 }
717 }
718 if (UCOP_SET_W) {
719 store_reg(s, UCOP_REG_N, addr);
720 } else {
721 dead_tmp(addr);
722 }
723}
724
725/* UniCore-F64 load/store multiple words */
Andreas Färbereb23b552012-03-14 01:38:23 +0100726static void do_ucf64_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +0800727{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200728 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800729 unsigned int i;
730 int j, n, freg;
731 TCGv tmp;
732 TCGv addr;
733
734 if (UCOP_REG_D != 0) {
735 ILLEGAL;
736 }
737 if (UCOP_REG_N == 31) {
738 ILLEGAL;
739 }
740 if ((insn << 24) == 0) {
741 ILLEGAL;
742 }
743
744 addr = load_reg(s, UCOP_REG_N);
745
746 n = 0;
747 for (i = 0; i < 8; i++) {
748 if (UCOP_SET(i)) {
749 n++;
750 }
751 }
752
753 if (UCOP_SET_U) {
754 if (UCOP_SET_P) { /* pre increment */
755 tcg_gen_addi_i32(addr, addr, 4);
756 } /* unnecessary to do anything when post increment */
757 } else {
758 if (UCOP_SET_P) { /* pre decrement */
759 tcg_gen_addi_i32(addr, addr, -(n * 4));
760 } else { /* post decrement */
761 if (n != 1) {
762 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
763 }
764 }
765 }
766
767 freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */
768
769 for (i = 0, j = 0; i < 8; i++, freg++) {
770 if (!UCOP_SET(i)) {
771 continue;
772 }
773
774 if (UCOP_SET_L) { /* load */
775 tmp = gen_ld32(addr, IS_USER(s));
776 ucf64_gen_st32(tmp, freg);
777 } else { /* store */
778 tmp = ucf64_gen_ld32(freg);
779 gen_st32(tmp, addr, IS_USER(s));
780 }
781
782 j++;
783 /* unnecessary to add after the last transfer */
784 if (j != n) {
785 tcg_gen_addi_i32(addr, addr, 4);
786 }
787 }
788
789 if (UCOP_SET_W) { /* write back */
790 if (UCOP_SET_U) {
791 if (!UCOP_SET_P) { /* post increment */
792 tcg_gen_addi_i32(addr, addr, 4);
793 } /* unnecessary to do anything when pre increment */
794 } else {
795 if (UCOP_SET_P) {
796 /* pre decrement */
797 if (n != 1) {
798 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
799 }
800 } else {
801 /* post decrement */
802 tcg_gen_addi_i32(addr, addr, -(n * 4));
803 }
804 }
805 store_reg(s, UCOP_REG_N, addr);
806 } else {
807 dead_tmp(addr);
808 }
809}
810
811/* UniCore-F64 mrc/mcr */
Andreas Färbereb23b552012-03-14 01:38:23 +0100812static void do_ucf64_trans(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +0800813{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200814 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +0800815 TCGv tmp;
816
817 if ((insn & 0xfe0003ff) == 0xe2000000) {
818 /* control register */
819 if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) {
820 ILLEGAL;
821 }
822 if (UCOP_SET(24)) {
823 /* CFF */
824 tmp = new_tmp();
825 gen_helper_ucf64_get_fpscr(tmp, cpu_env);
826 store_reg(s, UCOP_REG_D, tmp);
827 } else {
828 /* CTF */
829 tmp = load_reg(s, UCOP_REG_D);
830 gen_helper_ucf64_set_fpscr(cpu_env, tmp);
831 dead_tmp(tmp);
832 gen_lookup_tb(s);
833 }
834 return;
835 }
836 if ((insn & 0xfe0003ff) == 0xe0000000) {
837 /* general register */
838 if (UCOP_REG_D == 31) {
839 ILLEGAL;
840 }
841 if (UCOP_SET(24)) { /* MFF */
842 tmp = ucf64_gen_ld32(UCOP_REG_N);
843 store_reg(s, UCOP_REG_D, tmp);
844 } else { /* MTF */
845 tmp = load_reg(s, UCOP_REG_D);
846 ucf64_gen_st32(tmp, UCOP_REG_N);
847 }
848 return;
849 }
850 if ((insn & 0xfb000000) == 0xe9000000) {
851 /* MFFC */
852 if (UCOP_REG_D != 31) {
853 ILLEGAL;
854 }
855 if (UCOP_UCF64_COND & 0x8) {
856 ILLEGAL;
857 }
858
859 tmp = new_tmp();
860 tcg_gen_movi_i32(tmp, UCOP_UCF64_COND);
861 if (UCOP_SET(26)) {
862 tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
863 tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
864 gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env);
865 } else {
866 tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
867 tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
868 gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env);
869 }
870 dead_tmp(tmp);
871 return;
872 }
873 ILLEGAL;
874}
875
876/* UniCore-F64 convert instructions */
Andreas Färbereb23b552012-03-14 01:38:23 +0100877static void do_ucf64_fcvt(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +0800878{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200879 UniCore32CPU *cpu = uc32_env_get_cpu(env);
880
Guan Xuetao6e64da32011-04-12 16:25:59 +0800881 if (UCOP_UCF64_FMT == 3) {
882 ILLEGAL;
883 }
884 if (UCOP_REG_N != 0) {
885 ILLEGAL;
886 }
887 switch (UCOP_UCF64_FUNC) {
888 case 0: /* cvt.s */
889 switch (UCOP_UCF64_FMT) {
890 case 1 /* d */:
891 tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
892 gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env);
893 tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
894 break;
895 case 2 /* w */:
896 tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
897 gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env);
898 tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
899 break;
900 default /* s */:
901 ILLEGAL;
902 break;
903 }
904 break;
905 case 1: /* cvt.d */
906 switch (UCOP_UCF64_FMT) {
907 case 0 /* s */:
908 tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
909 gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env);
910 tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
911 break;
912 case 2 /* w */:
913 tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
914 gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env);
915 tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
916 break;
917 default /* d */:
918 ILLEGAL;
919 break;
920 }
921 break;
922 case 4: /* cvt.w */
923 switch (UCOP_UCF64_FMT) {
924 case 0 /* s */:
925 tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
926 gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env);
927 tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
928 break;
929 case 1 /* d */:
930 tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
931 gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env);
932 tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
933 break;
934 default /* w */:
935 ILLEGAL;
936 break;
937 }
938 break;
939 default:
940 ILLEGAL;
941 }
942}
943
944/* UniCore-F64 compare instructions */
Andreas Färbereb23b552012-03-14 01:38:23 +0100945static void do_ucf64_fcmp(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +0800946{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200947 UniCore32CPU *cpu = uc32_env_get_cpu(env);
948
Guan Xuetao6e64da32011-04-12 16:25:59 +0800949 if (UCOP_SET(25)) {
950 ILLEGAL;
951 }
952 if (UCOP_REG_D != 0) {
953 ILLEGAL;
954 }
955
956 ILLEGAL; /* TODO */
957 if (UCOP_SET(24)) {
958 tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
959 tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
960 /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */
961 } else {
962 tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
963 tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
964 /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */
965 }
966}
967
968#define gen_helper_ucf64_movs(x, y) do { } while (0)
969#define gen_helper_ucf64_movd(x, y) do { } while (0)
970
971#define UCF64_OP1(name) do { \
972 if (UCOP_REG_N != 0) { \
973 ILLEGAL; \
974 } \
975 switch (UCOP_UCF64_FMT) { \
976 case 0 /* s */: \
977 tcg_gen_ld_i32(cpu_F0s, cpu_env, \
978 ucf64_reg_offset(UCOP_REG_M)); \
979 gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \
980 tcg_gen_st_i32(cpu_F0s, cpu_env, \
981 ucf64_reg_offset(UCOP_REG_D)); \
982 break; \
983 case 1 /* d */: \
984 tcg_gen_ld_i64(cpu_F0d, cpu_env, \
985 ucf64_reg_offset(UCOP_REG_M)); \
986 gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \
987 tcg_gen_st_i64(cpu_F0d, cpu_env, \
988 ucf64_reg_offset(UCOP_REG_D)); \
989 break; \
990 case 2 /* w */: \
991 ILLEGAL; \
992 break; \
993 } \
994 } while (0)
995
996#define UCF64_OP2(name) do { \
997 switch (UCOP_UCF64_FMT) { \
998 case 0 /* s */: \
999 tcg_gen_ld_i32(cpu_F0s, cpu_env, \
1000 ucf64_reg_offset(UCOP_REG_N)); \
1001 tcg_gen_ld_i32(cpu_F1s, cpu_env, \
1002 ucf64_reg_offset(UCOP_REG_M)); \
1003 gen_helper_ucf64_##name##s(cpu_F0s, \
1004 cpu_F0s, cpu_F1s, cpu_env); \
1005 tcg_gen_st_i32(cpu_F0s, cpu_env, \
1006 ucf64_reg_offset(UCOP_REG_D)); \
1007 break; \
1008 case 1 /* d */: \
1009 tcg_gen_ld_i64(cpu_F0d, cpu_env, \
1010 ucf64_reg_offset(UCOP_REG_N)); \
1011 tcg_gen_ld_i64(cpu_F1d, cpu_env, \
1012 ucf64_reg_offset(UCOP_REG_M)); \
1013 gen_helper_ucf64_##name##d(cpu_F0d, \
1014 cpu_F0d, cpu_F1d, cpu_env); \
1015 tcg_gen_st_i64(cpu_F0d, cpu_env, \
1016 ucf64_reg_offset(UCOP_REG_D)); \
1017 break; \
1018 case 2 /* w */: \
1019 ILLEGAL; \
1020 break; \
1021 } \
1022 } while (0)
1023
1024/* UniCore-F64 data processing */
Andreas Färbereb23b552012-03-14 01:38:23 +01001025static void do_ucf64_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001026{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001027 UniCore32CPU *cpu = uc32_env_get_cpu(env);
1028
Guan Xuetao6e64da32011-04-12 16:25:59 +08001029 if (UCOP_UCF64_FMT == 3) {
1030 ILLEGAL;
1031 }
1032 switch (UCOP_UCF64_FUNC) {
1033 case 0: /* add */
1034 UCF64_OP2(add);
1035 break;
1036 case 1: /* sub */
1037 UCF64_OP2(sub);
1038 break;
1039 case 2: /* mul */
1040 UCF64_OP2(mul);
1041 break;
1042 case 4: /* div */
1043 UCF64_OP2(div);
1044 break;
1045 case 5: /* abs */
1046 UCF64_OP1(abs);
1047 break;
1048 case 6: /* mov */
1049 UCF64_OP1(mov);
1050 break;
1051 case 7: /* neg */
1052 UCF64_OP1(neg);
1053 break;
1054 default:
1055 ILLEGAL;
1056 }
1057}
1058
1059/* Disassemble an F64 instruction */
Andreas Färbereb23b552012-03-14 01:38:23 +01001060static void disas_ucf64_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001061{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001062 UniCore32CPU *cpu = uc32_env_get_cpu(env);
1063
Guan Xuetao6e64da32011-04-12 16:25:59 +08001064 if (!UCOP_SET(29)) {
1065 if (UCOP_SET(26)) {
1066 do_ucf64_ldst_m(env, s, insn);
1067 } else {
1068 do_ucf64_ldst_i(env, s, insn);
1069 }
1070 } else {
1071 if (UCOP_SET(5)) {
1072 switch ((insn >> 26) & 0x3) {
1073 case 0:
1074 do_ucf64_datap(env, s, insn);
1075 break;
1076 case 1:
1077 ILLEGAL;
1078 break;
1079 case 2:
1080 do_ucf64_fcvt(env, s, insn);
1081 break;
1082 case 3:
1083 do_ucf64_fcmp(env, s, insn);
1084 break;
1085 }
1086 } else {
1087 do_ucf64_trans(env, s, insn);
1088 }
1089 }
1090}
1091
1092static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
1093{
1094 TranslationBlock *tb;
1095
1096 tb = s->tb;
1097 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
1098 tcg_gen_goto_tb(n);
1099 gen_set_pc_im(dest);
Richard Henderson8cfd0492013-08-20 15:53:10 -07001100 tcg_gen_exit_tb((uintptr_t)tb + n);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001101 } else {
1102 gen_set_pc_im(dest);
1103 tcg_gen_exit_tb(0);
1104 }
1105}
1106
1107static inline void gen_jmp(DisasContext *s, uint32_t dest)
1108{
1109 if (unlikely(s->singlestep_enabled)) {
1110 /* An indirect jump so that we still trigger the debug exception. */
1111 gen_bx_im(s, dest);
1112 } else {
1113 gen_goto_tb(s, 0, dest);
1114 s->is_jmp = DISAS_TB_JUMP;
1115 }
1116}
1117
Guan Xuetao6e64da32011-04-12 16:25:59 +08001118/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
1119static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0)
1120{
1121 TCGv tmp;
1122 if (bsr) {
1123 /* ??? This is also undefined in system mode. */
1124 if (IS_USER(s)) {
1125 return 1;
1126 }
1127
1128 tmp = load_cpu_field(bsr);
1129 tcg_gen_andi_i32(tmp, tmp, ~mask);
1130 tcg_gen_andi_i32(t0, t0, mask);
1131 tcg_gen_or_i32(tmp, tmp, t0);
1132 store_cpu_field(tmp, bsr);
1133 } else {
1134 gen_set_asr(t0, mask);
1135 }
1136 dead_tmp(t0);
1137 gen_lookup_tb(s);
1138 return 0;
1139}
1140
1141/* Generate an old-style exception return. Marks pc as dead. */
1142static void gen_exception_return(DisasContext *s, TCGv pc)
1143{
1144 TCGv tmp;
1145 store_reg(s, 31, pc);
1146 tmp = load_cpu_field(bsr);
1147 gen_set_asr(tmp, 0xffffffff);
1148 dead_tmp(tmp);
1149 s->is_jmp = DISAS_UPDATE;
1150}
1151
Guan Xuetao527d9972012-08-10 14:42:22 +08001152static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s,
1153 uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001154{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001155 UniCore32CPU *cpu = uc32_env_get_cpu(env);
1156
Guan Xuetao6e64da32011-04-12 16:25:59 +08001157 switch (UCOP_CPNUM) {
Guan Xuetao527d9972012-08-10 14:42:22 +08001158#ifndef CONFIG_USER_ONLY
1159 case 0:
1160 disas_cp0_insn(env, s, insn);
1161 break;
1162 case 1:
1163 disas_ocd_insn(env, s, insn);
1164 break;
1165#endif
Guan Xuetao6e64da32011-04-12 16:25:59 +08001166 case 2:
1167 disas_ucf64_insn(env, s, insn);
1168 break;
1169 default:
1170 /* Unknown coprocessor. */
Andreas Färbera47dddd2013-09-03 17:38:47 +02001171 cpu_abort(CPU(cpu), "Unknown coprocessor!");
Guan Xuetao6e64da32011-04-12 16:25:59 +08001172 }
1173}
1174
Guan Xuetao6e64da32011-04-12 16:25:59 +08001175/* data processing instructions */
Andreas Färbereb23b552012-03-14 01:38:23 +01001176static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001177{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001178 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001179 TCGv tmp;
1180 TCGv tmp2;
1181 int logic_cc;
1182
1183 if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) {
1184 if (UCOP_SET(23)) { /* CMOV instructions */
1185 if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) {
1186 ILLEGAL;
1187 }
1188 /* if not always execute, we generate a conditional jump to
1189 next instruction */
1190 s->condlabel = gen_new_label();
1191 gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel);
1192 s->condjmp = 1;
1193 }
1194 }
1195
1196 logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24);
1197
1198 if (UCOP_SET(29)) {
1199 unsigned int val;
1200 /* immediate operand */
1201 val = UCOP_IMM_9;
1202 if (UCOP_SH_IM) {
1203 val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
1204 }
1205 tmp2 = new_tmp();
1206 tcg_gen_movi_i32(tmp2, val);
1207 if (logic_cc && UCOP_SH_IM) {
1208 gen_set_CF_bit31(tmp2);
1209 }
1210 } else {
1211 /* register */
1212 tmp2 = load_reg(s, UCOP_REG_M);
1213 if (UCOP_SET(5)) {
1214 tmp = load_reg(s, UCOP_REG_S);
1215 gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc);
1216 } else {
1217 gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc);
1218 }
1219 }
1220
1221 if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
1222 tmp = load_reg(s, UCOP_REG_N);
1223 } else {
1224 TCGV_UNUSED(tmp);
1225 }
1226
1227 switch (UCOP_OPCODES) {
1228 case 0x00:
1229 tcg_gen_and_i32(tmp, tmp, tmp2);
1230 if (logic_cc) {
1231 gen_logic_CC(tmp);
1232 }
1233 store_reg_bx(s, UCOP_REG_D, tmp);
1234 break;
1235 case 0x01:
1236 tcg_gen_xor_i32(tmp, tmp, tmp2);
1237 if (logic_cc) {
1238 gen_logic_CC(tmp);
1239 }
1240 store_reg_bx(s, UCOP_REG_D, tmp);
1241 break;
1242 case 0x02:
1243 if (UCOP_SET_S && UCOP_REG_D == 31) {
1244 /* SUBS r31, ... is used for exception return. */
1245 if (IS_USER(s)) {
1246 ILLEGAL;
1247 }
Blue Swirl04a130e2012-09-02 07:42:33 +00001248 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001249 gen_exception_return(s, tmp);
1250 } else {
1251 if (UCOP_SET_S) {
Blue Swirl04a130e2012-09-02 07:42:33 +00001252 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001253 } else {
1254 tcg_gen_sub_i32(tmp, tmp, tmp2);
1255 }
1256 store_reg_bx(s, UCOP_REG_D, tmp);
1257 }
1258 break;
1259 case 0x03:
1260 if (UCOP_SET_S) {
Blue Swirl04a130e2012-09-02 07:42:33 +00001261 gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001262 } else {
1263 tcg_gen_sub_i32(tmp, tmp2, tmp);
1264 }
1265 store_reg_bx(s, UCOP_REG_D, tmp);
1266 break;
1267 case 0x04:
1268 if (UCOP_SET_S) {
Blue Swirl04a130e2012-09-02 07:42:33 +00001269 gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001270 } else {
1271 tcg_gen_add_i32(tmp, tmp, tmp2);
1272 }
1273 store_reg_bx(s, UCOP_REG_D, tmp);
1274 break;
1275 case 0x05:
1276 if (UCOP_SET_S) {
Blue Swirl04a130e2012-09-02 07:42:33 +00001277 gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001278 } else {
1279 gen_add_carry(tmp, tmp, tmp2);
1280 }
1281 store_reg_bx(s, UCOP_REG_D, tmp);
1282 break;
1283 case 0x06:
1284 if (UCOP_SET_S) {
Blue Swirl04a130e2012-09-02 07:42:33 +00001285 gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001286 } else {
1287 gen_sub_carry(tmp, tmp, tmp2);
1288 }
1289 store_reg_bx(s, UCOP_REG_D, tmp);
1290 break;
1291 case 0x07:
1292 if (UCOP_SET_S) {
Blue Swirl04a130e2012-09-02 07:42:33 +00001293 gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001294 } else {
1295 gen_sub_carry(tmp, tmp2, tmp);
1296 }
1297 store_reg_bx(s, UCOP_REG_D, tmp);
1298 break;
1299 case 0x08:
1300 if (UCOP_SET_S) {
1301 tcg_gen_and_i32(tmp, tmp, tmp2);
1302 gen_logic_CC(tmp);
1303 }
1304 dead_tmp(tmp);
1305 break;
1306 case 0x09:
1307 if (UCOP_SET_S) {
1308 tcg_gen_xor_i32(tmp, tmp, tmp2);
1309 gen_logic_CC(tmp);
1310 }
1311 dead_tmp(tmp);
1312 break;
1313 case 0x0a:
1314 if (UCOP_SET_S) {
Blue Swirl04a130e2012-09-02 07:42:33 +00001315 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001316 }
1317 dead_tmp(tmp);
1318 break;
1319 case 0x0b:
1320 if (UCOP_SET_S) {
Blue Swirl04a130e2012-09-02 07:42:33 +00001321 gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001322 }
1323 dead_tmp(tmp);
1324 break;
1325 case 0x0c:
1326 tcg_gen_or_i32(tmp, tmp, tmp2);
1327 if (logic_cc) {
1328 gen_logic_CC(tmp);
1329 }
1330 store_reg_bx(s, UCOP_REG_D, tmp);
1331 break;
1332 case 0x0d:
1333 if (logic_cc && UCOP_REG_D == 31) {
1334 /* MOVS r31, ... is used for exception return. */
1335 if (IS_USER(s)) {
1336 ILLEGAL;
1337 }
1338 gen_exception_return(s, tmp2);
1339 } else {
1340 if (logic_cc) {
1341 gen_logic_CC(tmp2);
1342 }
1343 store_reg_bx(s, UCOP_REG_D, tmp2);
1344 }
1345 break;
1346 case 0x0e:
1347 tcg_gen_andc_i32(tmp, tmp, tmp2);
1348 if (logic_cc) {
1349 gen_logic_CC(tmp);
1350 }
1351 store_reg_bx(s, UCOP_REG_D, tmp);
1352 break;
1353 default:
1354 case 0x0f:
1355 tcg_gen_not_i32(tmp2, tmp2);
1356 if (logic_cc) {
1357 gen_logic_CC(tmp2);
1358 }
1359 store_reg_bx(s, UCOP_REG_D, tmp2);
1360 break;
1361 }
1362 if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
1363 dead_tmp(tmp2);
1364 }
1365}
1366
1367/* multiply */
Andreas Färbereb23b552012-03-14 01:38:23 +01001368static void do_mult(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001369{
Richard Hendersond1f8cd82013-02-19 23:52:24 -08001370 TCGv tmp, tmp2, tmp3, tmp4;
Guan Xuetao6e64da32011-04-12 16:25:59 +08001371
1372 if (UCOP_SET(27)) {
1373 /* 64 bit mul */
1374 tmp = load_reg(s, UCOP_REG_M);
1375 tmp2 = load_reg(s, UCOP_REG_N);
1376 if (UCOP_SET(26)) {
Richard Hendersond1f8cd82013-02-19 23:52:24 -08001377 tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001378 } else {
Richard Hendersond1f8cd82013-02-19 23:52:24 -08001379 tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001380 }
1381 if (UCOP_SET(25)) { /* mult accumulate */
Richard Hendersond1f8cd82013-02-19 23:52:24 -08001382 tmp3 = load_reg(s, UCOP_REG_LO);
1383 tmp4 = load_reg(s, UCOP_REG_HI);
1384 tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, tmp3, tmp4);
1385 dead_tmp(tmp3);
1386 dead_tmp(tmp4);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001387 }
Richard Hendersond1f8cd82013-02-19 23:52:24 -08001388 store_reg(s, UCOP_REG_LO, tmp);
1389 store_reg(s, UCOP_REG_HI, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001390 } else {
1391 /* 32 bit mul */
1392 tmp = load_reg(s, UCOP_REG_M);
1393 tmp2 = load_reg(s, UCOP_REG_N);
1394 tcg_gen_mul_i32(tmp, tmp, tmp2);
1395 dead_tmp(tmp2);
1396 if (UCOP_SET(25)) {
1397 /* Add */
1398 tmp2 = load_reg(s, UCOP_REG_S);
1399 tcg_gen_add_i32(tmp, tmp, tmp2);
1400 dead_tmp(tmp2);
1401 }
1402 if (UCOP_SET_S) {
1403 gen_logic_CC(tmp);
1404 }
1405 store_reg(s, UCOP_REG_D, tmp);
1406 }
1407}
1408
1409/* miscellaneous instructions */
Andreas Färbereb23b552012-03-14 01:38:23 +01001410static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001411{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001412 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001413 unsigned int val;
1414 TCGv tmp;
1415
1416 if ((insn & 0xffffffe0) == 0x10ffc120) {
1417 /* Trivial implementation equivalent to bx. */
1418 tmp = load_reg(s, UCOP_REG_M);
1419 gen_bx(s, tmp);
1420 return;
1421 }
1422
1423 if ((insn & 0xfbffc000) == 0x30ffc000) {
1424 /* PSR = immediate */
1425 val = UCOP_IMM_9;
1426 if (UCOP_SH_IM) {
1427 val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
1428 }
1429 tmp = new_tmp();
1430 tcg_gen_movi_i32(tmp, val);
1431 if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
1432 ILLEGAL;
1433 }
1434 return;
1435 }
1436
1437 if ((insn & 0xfbffffe0) == 0x12ffc020) {
1438 /* PSR.flag = reg */
1439 tmp = load_reg(s, UCOP_REG_M);
1440 if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) {
1441 ILLEGAL;
1442 }
1443 return;
1444 }
1445
1446 if ((insn & 0xfbffffe0) == 0x10ffc020) {
1447 /* PSR = reg */
1448 tmp = load_reg(s, UCOP_REG_M);
1449 if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
1450 ILLEGAL;
1451 }
1452 return;
1453 }
1454
1455 if ((insn & 0xfbf83fff) == 0x10f80000) {
1456 /* reg = PSR */
1457 if (UCOP_SET_B) {
1458 if (IS_USER(s)) {
1459 ILLEGAL;
1460 }
1461 tmp = load_cpu_field(bsr);
1462 } else {
1463 tmp = new_tmp();
Blue Swirl04a130e2012-09-02 07:42:33 +00001464 gen_helper_asr_read(tmp, cpu_env);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001465 }
1466 store_reg(s, UCOP_REG_D, tmp);
1467 return;
1468 }
1469
1470 if ((insn & 0xfbf83fe0) == 0x12f80120) {
1471 /* clz */
1472 tmp = load_reg(s, UCOP_REG_M);
1473 if (UCOP_SET(26)) {
1474 gen_helper_clo(tmp, tmp);
1475 } else {
1476 gen_helper_clz(tmp, tmp);
1477 }
1478 store_reg(s, UCOP_REG_D, tmp);
1479 return;
1480 }
1481
1482 /* otherwise */
1483 ILLEGAL;
1484}
1485
1486/* load/store I_offset and R_offset */
Andreas Färbereb23b552012-03-14 01:38:23 +01001487static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001488{
Guan Xuetaoef031682012-08-10 14:42:26 +08001489 unsigned int mmu_idx;
Guan Xuetao6e64da32011-04-12 16:25:59 +08001490 TCGv tmp;
1491 TCGv tmp2;
1492
1493 tmp2 = load_reg(s, UCOP_REG_N);
Guan Xuetaoef031682012-08-10 14:42:26 +08001494 mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
Guan Xuetao6e64da32011-04-12 16:25:59 +08001495
1496 /* immediate */
1497 if (UCOP_SET_P) {
1498 gen_add_data_offset(s, insn, tmp2);
1499 }
1500
1501 if (UCOP_SET_L) {
1502 /* load */
1503 if (UCOP_SET_B) {
Guan Xuetaoef031682012-08-10 14:42:26 +08001504 tmp = gen_ld8u(tmp2, mmu_idx);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001505 } else {
Guan Xuetaoef031682012-08-10 14:42:26 +08001506 tmp = gen_ld32(tmp2, mmu_idx);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001507 }
1508 } else {
1509 /* store */
1510 tmp = load_reg(s, UCOP_REG_D);
1511 if (UCOP_SET_B) {
Guan Xuetaoef031682012-08-10 14:42:26 +08001512 gen_st8(tmp, tmp2, mmu_idx);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001513 } else {
Guan Xuetaoef031682012-08-10 14:42:26 +08001514 gen_st32(tmp, tmp2, mmu_idx);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001515 }
1516 }
1517 if (!UCOP_SET_P) {
1518 gen_add_data_offset(s, insn, tmp2);
1519 store_reg(s, UCOP_REG_N, tmp2);
1520 } else if (UCOP_SET_W) {
1521 store_reg(s, UCOP_REG_N, tmp2);
1522 } else {
1523 dead_tmp(tmp2);
1524 }
1525 if (UCOP_SET_L) {
1526 /* Complete the load. */
1527 if (UCOP_REG_D == 31) {
1528 gen_bx(s, tmp);
1529 } else {
1530 store_reg(s, UCOP_REG_D, tmp);
1531 }
1532 }
1533}
1534
1535/* SWP instruction */
Andreas Färbereb23b552012-03-14 01:38:23 +01001536static void do_swap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001537{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001538 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001539 TCGv addr;
1540 TCGv tmp;
1541 TCGv tmp2;
1542
1543 if ((insn & 0xff003fe0) != 0x40000120) {
1544 ILLEGAL;
1545 }
1546
1547 /* ??? This is not really atomic. However we know
1548 we never have multiple CPUs running in parallel,
1549 so it is good enough. */
1550 addr = load_reg(s, UCOP_REG_N);
1551 tmp = load_reg(s, UCOP_REG_M);
1552 if (UCOP_SET_B) {
1553 tmp2 = gen_ld8u(addr, IS_USER(s));
1554 gen_st8(tmp, addr, IS_USER(s));
1555 } else {
1556 tmp2 = gen_ld32(addr, IS_USER(s));
1557 gen_st32(tmp, addr, IS_USER(s));
1558 }
1559 dead_tmp(addr);
1560 store_reg(s, UCOP_REG_D, tmp2);
1561}
1562
1563/* load/store hw/sb */
Andreas Färbereb23b552012-03-14 01:38:23 +01001564static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001565{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001566 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001567 TCGv addr;
1568 TCGv tmp;
1569
1570 if (UCOP_SH_OP == 0) {
1571 do_swap(env, s, insn);
1572 return;
1573 }
1574
1575 addr = load_reg(s, UCOP_REG_N);
1576 if (UCOP_SET_P) {
1577 gen_add_datah_offset(s, insn, addr);
1578 }
1579
1580 if (UCOP_SET_L) { /* load */
1581 switch (UCOP_SH_OP) {
1582 case 1:
1583 tmp = gen_ld16u(addr, IS_USER(s));
1584 break;
1585 case 2:
1586 tmp = gen_ld8s(addr, IS_USER(s));
1587 break;
1588 default: /* see do_swap */
1589 case 3:
1590 tmp = gen_ld16s(addr, IS_USER(s));
1591 break;
1592 }
1593 } else { /* store */
1594 if (UCOP_SH_OP != 1) {
1595 ILLEGAL;
1596 }
1597 tmp = load_reg(s, UCOP_REG_D);
1598 gen_st16(tmp, addr, IS_USER(s));
1599 }
1600 /* Perform base writeback before the loaded value to
1601 ensure correct behavior with overlapping index registers. */
1602 if (!UCOP_SET_P) {
1603 gen_add_datah_offset(s, insn, addr);
1604 store_reg(s, UCOP_REG_N, addr);
1605 } else if (UCOP_SET_W) {
1606 store_reg(s, UCOP_REG_N, addr);
1607 } else {
1608 dead_tmp(addr);
1609 }
1610 if (UCOP_SET_L) {
1611 /* Complete the load. */
1612 store_reg(s, UCOP_REG_D, tmp);
1613 }
1614}
1615
1616/* load/store multiple words */
Andreas Färbereb23b552012-03-14 01:38:23 +01001617static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001618{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001619 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetaoef031682012-08-10 14:42:26 +08001620 unsigned int val, i, mmu_idx;
Guan Xuetao6e64da32011-04-12 16:25:59 +08001621 int j, n, reg, user, loaded_base;
1622 TCGv tmp;
1623 TCGv tmp2;
1624 TCGv addr;
1625 TCGv loaded_var;
1626
1627 if (UCOP_SET(7)) {
1628 ILLEGAL;
1629 }
1630 /* XXX: store correct base if write back */
1631 user = 0;
1632 if (UCOP_SET_B) { /* S bit in instruction table */
1633 if (IS_USER(s)) {
1634 ILLEGAL; /* only usable in supervisor mode */
1635 }
1636 if (UCOP_SET(18) == 0) { /* pc reg */
1637 user = 1;
1638 }
1639 }
1640
Guan Xuetaoef031682012-08-10 14:42:26 +08001641 mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
Guan Xuetao6e64da32011-04-12 16:25:59 +08001642 addr = load_reg(s, UCOP_REG_N);
1643
1644 /* compute total size */
1645 loaded_base = 0;
1646 TCGV_UNUSED(loaded_var);
1647 n = 0;
1648 for (i = 0; i < 6; i++) {
1649 if (UCOP_SET(i)) {
1650 n++;
1651 }
1652 }
1653 for (i = 9; i < 19; i++) {
1654 if (UCOP_SET(i)) {
1655 n++;
1656 }
1657 }
1658 /* XXX: test invalid n == 0 case ? */
1659 if (UCOP_SET_U) {
1660 if (UCOP_SET_P) {
1661 /* pre increment */
1662 tcg_gen_addi_i32(addr, addr, 4);
1663 } else {
1664 /* post increment */
1665 }
1666 } else {
1667 if (UCOP_SET_P) {
1668 /* pre decrement */
1669 tcg_gen_addi_i32(addr, addr, -(n * 4));
1670 } else {
1671 /* post decrement */
1672 if (n != 1) {
1673 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
1674 }
1675 }
1676 }
1677
1678 j = 0;
1679 reg = UCOP_SET(6) ? 16 : 0;
1680 for (i = 0; i < 19; i++, reg++) {
1681 if (i == 6) {
1682 i = i + 3;
1683 }
1684 if (UCOP_SET(i)) {
1685 if (UCOP_SET_L) { /* load */
Guan Xuetaoef031682012-08-10 14:42:26 +08001686 tmp = gen_ld32(addr, mmu_idx);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001687 if (reg == 31) {
1688 gen_bx(s, tmp);
1689 } else if (user) {
1690 tmp2 = tcg_const_i32(reg);
Blue Swirl04a130e2012-09-02 07:42:33 +00001691 gen_helper_set_user_reg(cpu_env, tmp2, tmp);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001692 tcg_temp_free_i32(tmp2);
1693 dead_tmp(tmp);
1694 } else if (reg == UCOP_REG_N) {
1695 loaded_var = tmp;
1696 loaded_base = 1;
1697 } else {
1698 store_reg(s, reg, tmp);
1699 }
1700 } else { /* store */
1701 if (reg == 31) {
1702 /* special case: r31 = PC + 4 */
1703 val = (long)s->pc;
1704 tmp = new_tmp();
1705 tcg_gen_movi_i32(tmp, val);
1706 } else if (user) {
1707 tmp = new_tmp();
1708 tmp2 = tcg_const_i32(reg);
Blue Swirl04a130e2012-09-02 07:42:33 +00001709 gen_helper_get_user_reg(tmp, cpu_env, tmp2);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001710 tcg_temp_free_i32(tmp2);
1711 } else {
1712 tmp = load_reg(s, reg);
1713 }
Guan Xuetaoef031682012-08-10 14:42:26 +08001714 gen_st32(tmp, addr, mmu_idx);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001715 }
1716 j++;
1717 /* no need to add after the last transfer */
1718 if (j != n) {
1719 tcg_gen_addi_i32(addr, addr, 4);
1720 }
1721 }
1722 }
1723 if (UCOP_SET_W) { /* write back */
1724 if (UCOP_SET_U) {
1725 if (UCOP_SET_P) {
1726 /* pre increment */
1727 } else {
1728 /* post increment */
1729 tcg_gen_addi_i32(addr, addr, 4);
1730 }
1731 } else {
1732 if (UCOP_SET_P) {
1733 /* pre decrement */
1734 if (n != 1) {
1735 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
1736 }
1737 } else {
1738 /* post decrement */
1739 tcg_gen_addi_i32(addr, addr, -(n * 4));
1740 }
1741 }
1742 store_reg(s, UCOP_REG_N, addr);
1743 } else {
1744 dead_tmp(addr);
1745 }
1746 if (loaded_base) {
1747 store_reg(s, UCOP_REG_N, loaded_var);
1748 }
1749 if (UCOP_SET_B && !user) {
1750 /* Restore ASR from BSR. */
1751 tmp = load_cpu_field(bsr);
1752 gen_set_asr(tmp, 0xffffffff);
1753 dead_tmp(tmp);
1754 s->is_jmp = DISAS_UPDATE;
1755 }
1756}
1757
1758/* branch (and link) */
Andreas Färbereb23b552012-03-14 01:38:23 +01001759static void do_branch(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001760{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001761 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001762 unsigned int val;
1763 int32_t offset;
1764 TCGv tmp;
1765
1766 if (UCOP_COND == 0xf) {
1767 ILLEGAL;
1768 }
1769
1770 if (UCOP_COND != 0xe) {
1771 /* if not always execute, we generate a conditional jump to
1772 next instruction */
1773 s->condlabel = gen_new_label();
1774 gen_test_cc(UCOP_COND ^ 1, s->condlabel);
1775 s->condjmp = 1;
1776 }
1777
1778 val = (int32_t)s->pc;
1779 if (UCOP_SET_L) {
1780 tmp = new_tmp();
1781 tcg_gen_movi_i32(tmp, val);
1782 store_reg(s, 30, tmp);
1783 }
1784 offset = (((int32_t)insn << 8) >> 8);
1785 val += (offset << 2); /* unicore is pc+4 */
1786 gen_jmp(s, val);
1787}
1788
Andreas Färbereb23b552012-03-14 01:38:23 +01001789static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001790{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001791 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001792 unsigned int insn;
1793
Blue Swirl04a130e2012-09-02 07:42:33 +00001794 insn = cpu_ldl_code(env, s->pc);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001795 s->pc += 4;
1796
1797 /* UniCore instructions class:
1798 * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx
1799 * AAA : see switch case
1800 * BBBB : opcodes or cond or PUBW
1801 * C : S OR L
1802 * D : 8
1803 * E : 5
1804 */
1805 switch (insn >> 29) {
Gerd Hoffmannfa4e49c2011-09-07 15:02:16 +02001806 case 0x0:
Guan Xuetao6e64da32011-04-12 16:25:59 +08001807 if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) {
1808 do_mult(env, s, insn);
1809 break;
1810 }
1811
1812 if (UCOP_SET(8)) {
1813 do_misc(env, s, insn);
1814 break;
1815 }
Gerd Hoffmannfa4e49c2011-09-07 15:02:16 +02001816 case 0x1:
Guan Xuetao6e64da32011-04-12 16:25:59 +08001817 if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) {
1818 do_misc(env, s, insn);
1819 break;
1820 }
1821 do_datap(env, s, insn);
1822 break;
1823
Gerd Hoffmannfa4e49c2011-09-07 15:02:16 +02001824 case 0x2:
Guan Xuetao6e64da32011-04-12 16:25:59 +08001825 if (UCOP_SET(8) && UCOP_SET(5)) {
1826 do_ldst_hwsb(env, s, insn);
1827 break;
1828 }
1829 if (UCOP_SET(8) || UCOP_SET(5)) {
1830 ILLEGAL;
1831 }
Gerd Hoffmannfa4e49c2011-09-07 15:02:16 +02001832 case 0x3:
Guan Xuetao6e64da32011-04-12 16:25:59 +08001833 do_ldst_ir(env, s, insn);
1834 break;
1835
Gerd Hoffmannfa4e49c2011-09-07 15:02:16 +02001836 case 0x4:
Guan Xuetao6e64da32011-04-12 16:25:59 +08001837 if (UCOP_SET(8)) {
1838 ILLEGAL; /* extended instructions */
1839 }
1840 do_ldst_m(env, s, insn);
1841 break;
Gerd Hoffmannfa4e49c2011-09-07 15:02:16 +02001842 case 0x5:
Guan Xuetao6e64da32011-04-12 16:25:59 +08001843 do_branch(env, s, insn);
1844 break;
Gerd Hoffmannfa4e49c2011-09-07 15:02:16 +02001845 case 0x6:
Guan Xuetao6e64da32011-04-12 16:25:59 +08001846 /* Coprocessor. */
1847 disas_coproc_insn(env, s, insn);
1848 break;
Gerd Hoffmannfa4e49c2011-09-07 15:02:16 +02001849 case 0x7:
Guan Xuetao6e64da32011-04-12 16:25:59 +08001850 if (!UCOP_SET(28)) {
1851 disas_coproc_insn(env, s, insn);
1852 break;
1853 }
1854 if ((insn & 0xff000000) == 0xff000000) { /* syscall */
1855 gen_set_pc_im(s->pc);
1856 s->is_jmp = DISAS_SYSCALL;
1857 break;
1858 }
1859 ILLEGAL;
1860 }
Guan Xuetao6e64da32011-04-12 16:25:59 +08001861}
1862
Richard Henderson20157702015-12-11 09:17:45 -08001863/* generate intermediate code for basic block 'tb'. */
Richard Henderson4e5e1212015-09-01 20:01:40 -07001864void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
Guan Xuetao6e64da32011-04-12 16:25:59 +08001865{
Richard Henderson4e5e1212015-09-01 20:01:40 -07001866 UniCore32CPU *cpu = uc32_env_get_cpu(env);
Andreas Färbered2803d2013-06-21 20:20:45 +02001867 CPUState *cs = CPU(cpu);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001868 DisasContext dc1, *dc = &dc1;
Guan Xuetao6e64da32011-04-12 16:25:59 +08001869 target_ulong pc_start;
1870 uint32_t next_page_start;
1871 int num_insns;
1872 int max_insns;
1873
1874 /* generate intermediate code */
1875 num_temps = 0;
1876
1877 pc_start = tb->pc;
1878
1879 dc->tb = tb;
1880
Guan Xuetao6e64da32011-04-12 16:25:59 +08001881 dc->is_jmp = DISAS_NEXT;
1882 dc->pc = pc_start;
Andreas Färbered2803d2013-06-21 20:20:45 +02001883 dc->singlestep_enabled = cs->singlestep_enabled;
Guan Xuetao6e64da32011-04-12 16:25:59 +08001884 dc->condjmp = 0;
1885 cpu_F0s = tcg_temp_new_i32();
1886 cpu_F1s = tcg_temp_new_i32();
1887 cpu_F0d = tcg_temp_new_i64();
1888 cpu_F1d = tcg_temp_new_i64();
1889 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
Guan Xuetao6e64da32011-04-12 16:25:59 +08001890 num_insns = 0;
1891 max_insns = tb->cflags & CF_COUNT_MASK;
1892 if (max_insns == 0) {
1893 max_insns = CF_COUNT_MASK;
1894 }
Richard Henderson190ce7f2015-08-31 14:34:41 -07001895 if (max_insns > TCG_MAX_INSNS) {
1896 max_insns = TCG_MAX_INSNS;
1897 }
Guan Xuetao6e64da32011-04-12 16:25:59 +08001898
Guan Xuetaoef031682012-08-10 14:42:26 +08001899#ifndef CONFIG_USER_ONLY
1900 if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) {
1901 dc->user = 1;
1902 } else {
1903 dc->user = 0;
1904 }
1905#endif
1906
Paolo Bonzinicd42d5b2014-11-26 13:40:05 +03001907 gen_tb_start(tb);
Guan Xuetao6e64da32011-04-12 16:25:59 +08001908 do {
Richard Henderson667b8e22015-08-29 12:59:29 -07001909 tcg_gen_insn_start(dc->pc);
Richard Henderson959082f2015-09-17 14:25:46 -07001910 num_insns++;
Guan Xuetao6e64da32011-04-12 16:25:59 +08001911
Richard Hendersonb9330662015-09-17 15:58:10 -07001912 if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
1913 gen_set_pc_im(dc->pc);
1914 gen_exception(EXCP_DEBUG);
1915 dc->is_jmp = DISAS_JUMP;
Richard Henderson522a0d42015-10-13 22:07:49 +00001916 /* The address covered by the breakpoint must be included in
1917 [tb->pc, tb->pc + tb->size) in order to for it to be
1918 properly cleared -- thus we increment the PC here so that
1919 the logic setting tb->size below does the right thing. */
1920 dc->pc += 4;
Richard Hendersonb9330662015-09-17 15:58:10 -07001921 goto done_generating;
1922 }
1923
Richard Henderson959082f2015-09-17 14:25:46 -07001924 if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
Guan Xuetao6e64da32011-04-12 16:25:59 +08001925 gen_io_start();
1926 }
1927
1928 disas_uc32_insn(env, dc);
1929
1930 if (num_temps) {
1931 fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
1932 num_temps = 0;
1933 }
1934
1935 if (dc->condjmp && !dc->is_jmp) {
1936 gen_set_label(dc->condlabel);
1937 dc->condjmp = 0;
1938 }
1939 /* Translation stops when a conditional branch is encountered.
1940 * Otherwise the subsequent code could get translated several times.
1941 * Also stop translation when a page boundary is reached. This
1942 * ensures prefetch aborts occur at the right place. */
Richard Hendersonfe700ad2014-03-30 15:36:56 -07001943 } while (!dc->is_jmp && !tcg_op_buf_full() &&
Andreas Färbered2803d2013-06-21 20:20:45 +02001944 !cs->singlestep_enabled &&
Guan Xuetao6e64da32011-04-12 16:25:59 +08001945 !singlestep &&
1946 dc->pc < next_page_start &&
1947 num_insns < max_insns);
1948
1949 if (tb->cflags & CF_LAST_IO) {
1950 if (dc->condjmp) {
1951 /* FIXME: This can theoretically happen with self-modifying
1952 code. */
Andreas Färbera47dddd2013-09-03 17:38:47 +02001953 cpu_abort(cs, "IO on conditional branch instruction");
Guan Xuetao6e64da32011-04-12 16:25:59 +08001954 }
1955 gen_io_end();
1956 }
1957
1958 /* At this stage dc->condjmp will only be set when the skipped
1959 instruction was a conditional branch or trap, and the PC has
1960 already been written. */
Andreas Färbered2803d2013-06-21 20:20:45 +02001961 if (unlikely(cs->singlestep_enabled)) {
Guan Xuetao6e64da32011-04-12 16:25:59 +08001962 /* Make sure the pc is updated, and raise a debug exception. */
1963 if (dc->condjmp) {
1964 if (dc->is_jmp == DISAS_SYSCALL) {
1965 gen_exception(UC32_EXCP_PRIV);
1966 } else {
1967 gen_exception(EXCP_DEBUG);
1968 }
1969 gen_set_label(dc->condlabel);
1970 }
1971 if (dc->condjmp || !dc->is_jmp) {
1972 gen_set_pc_im(dc->pc);
1973 dc->condjmp = 0;
1974 }
1975 if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) {
1976 gen_exception(UC32_EXCP_PRIV);
1977 } else {
1978 gen_exception(EXCP_DEBUG);
1979 }
1980 } else {
1981 /* While branches must always occur at the end of an IT block,
1982 there are a few other things that can cause us to terminate
1983 the TB in the middel of an IT block:
1984 - Exception generating instructions (bkpt, swi, undefined).
1985 - Page boundaries.
1986 - Hardware watchpoints.
1987 Hardware breakpoints have already been handled and skip this code.
1988 */
1989 switch (dc->is_jmp) {
1990 case DISAS_NEXT:
1991 gen_goto_tb(dc, 1, dc->pc);
1992 break;
1993 default:
1994 case DISAS_JUMP:
1995 case DISAS_UPDATE:
1996 /* indicate that the hash table must be used to find the next TB */
1997 tcg_gen_exit_tb(0);
1998 break;
1999 case DISAS_TB_JUMP:
2000 /* nothing more to generate */
2001 break;
2002 case DISAS_SYSCALL:
2003 gen_exception(UC32_EXCP_PRIV);
2004 break;
2005 }
2006 if (dc->condjmp) {
2007 gen_set_label(dc->condlabel);
2008 gen_goto_tb(dc, 1, dc->pc);
2009 dc->condjmp = 0;
2010 }
2011 }
2012
2013done_generating:
Peter Maydell806f3522013-02-22 18:10:05 +00002014 gen_tb_end(tb, num_insns);
Guan Xuetao6e64da32011-04-12 16:25:59 +08002015
2016#ifdef DEBUG_DISAS
2017 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
2018 qemu_log("----------------\n");
2019 qemu_log("IN: %s\n", lookup_symbol(pc_start));
Peter Crosthwaited49190c2015-05-24 14:20:41 -07002020 log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
Guan Xuetao6e64da32011-04-12 16:25:59 +08002021 qemu_log("\n");
2022 }
2023#endif
Richard Henderson4e5e1212015-09-01 20:01:40 -07002024 tb->size = dc->pc - pc_start;
2025 tb->icount = num_insns;
Guan Xuetao6e64da32011-04-12 16:25:59 +08002026}
2027
2028static const char *cpu_mode_names[16] = {
2029 "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP",
2030 "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR"
2031};
2032
Guan Xuetao1e5cdaa2012-08-10 14:42:38 +08002033#undef UCF64_DUMP_STATE
Guan Xuetaoc5240d82012-08-10 14:42:37 +08002034#ifdef UCF64_DUMP_STATE
2035static void cpu_dump_state_ucf64(CPUUniCore32State *env, FILE *f,
2036 fprintf_function cpu_fprintf, int flags)
Guan Xuetao6e64da32011-04-12 16:25:59 +08002037{
2038 int i;
Guan Xuetao6e64da32011-04-12 16:25:59 +08002039 union {
2040 uint32_t i;
2041 float s;
2042 } s0, s1;
2043 CPU_DoubleU d;
2044 /* ??? This assumes float64 and double have the same layout.
2045 Oh well, it's only debug dumps. */
2046 union {
2047 float64 f64;
2048 double d;
2049 } d0;
Guan Xuetaoc5240d82012-08-10 14:42:37 +08002050
2051 for (i = 0; i < 16; i++) {
2052 d.d = env->ucf64.regs[i];
2053 s0.i = d.l.lower;
2054 s1.i = d.l.upper;
2055 d0.f64 = d.d;
2056 cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)",
2057 i * 2, (int)s0.i, s0.s,
2058 i * 2 + 1, (int)s1.i, s1.s);
2059 cpu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n",
2060 i, (uint64_t)d0.f64, d0.d);
2061 }
2062 cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
2063}
2064#else
2065#define cpu_dump_state_ucf64(env, file, pr, flags) do { } while (0)
Guan Xuetao6e64da32011-04-12 16:25:59 +08002066#endif
Guan Xuetaoc5240d82012-08-10 14:42:37 +08002067
Andreas Färber878096e2013-05-27 01:33:50 +02002068void uc32_cpu_dump_state(CPUState *cs, FILE *f,
2069 fprintf_function cpu_fprintf, int flags)
Guan Xuetaoc5240d82012-08-10 14:42:37 +08002070{
Andreas Färber878096e2013-05-27 01:33:50 +02002071 UniCore32CPU *cpu = UNICORE32_CPU(cs);
2072 CPUUniCore32State *env = &cpu->env;
Guan Xuetaoc5240d82012-08-10 14:42:37 +08002073 int i;
Guan Xuetao6e64da32011-04-12 16:25:59 +08002074 uint32_t psr;
2075
2076 for (i = 0; i < 32; i++) {
2077 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2078 if ((i % 4) == 3) {
2079 cpu_fprintf(f, "\n");
2080 } else {
2081 cpu_fprintf(f, " ");
2082 }
2083 }
2084 psr = cpu_asr_read(env);
2085 cpu_fprintf(f, "PSR=%08x %c%c%c%c %s\n",
2086 psr,
2087 psr & (1 << 31) ? 'N' : '-',
2088 psr & (1 << 30) ? 'Z' : '-',
2089 psr & (1 << 29) ? 'C' : '-',
2090 psr & (1 << 28) ? 'V' : '-',
2091 cpu_mode_names[psr & 0xf]);
2092
Guan Xuetaoc5240d82012-08-10 14:42:37 +08002093 cpu_dump_state_ucf64(env, f, cpu_fprintf, flags);
Guan Xuetao6e64da32011-04-12 16:25:59 +08002094}
2095
Richard Hendersonbad729e2015-09-01 15:51:12 -07002096void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb,
2097 target_ulong *data)
Guan Xuetao6e64da32011-04-12 16:25:59 +08002098{
Richard Hendersonbad729e2015-09-01 15:51:12 -07002099 env->regs[31] = data[0];
Guan Xuetao6e64da32011-04-12 16:25:59 +08002100}