Statistics
| Branch: | Revision:

root / target-unicore32 / translate.c @ 4d5b97da

History | View | Annotate | Download (60 kB)

1
/*
2
 *  UniCore32 translation
3
 *
4
 * Copyright (C) 2010-2012 Guan Xuetao
5
 *
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
8
 * published by the Free Software Foundation, or (at your option) any
9
 * later version. See the COPYING file in the top-level directory.
10
 */
11
#include <stdarg.h>
12
#include <stdlib.h>
13
#include <stdio.h>
14
#include <string.h>
15
#include <inttypes.h>
16

    
17
#include "cpu.h"
18
#include "disas.h"
19
#include "tcg-op.h"
20
#include "qemu-log.h"
21

    
22
#include "helper.h"
23
#define GEN_HELPER 1
24
#include "helper.h"
25

    
26
/* internal defines */
27
typedef 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.  */
33
    int condlabel;
34
    struct TranslationBlock *tb;
35
    int singlestep_enabled;
36
#ifndef CONFIG_USER_ONLY
37
    int user;
38
#endif
39
} DisasContext;
40

    
41
#ifndef CONFIG_USER_ONLY
42
#define IS_USER(s)      (s->user)
43
#else
44
#define IS_USER(s)      1
45
#endif
46

    
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

    
51
static TCGv_ptr cpu_env;
52
static TCGv_i32 cpu_R[32];
53

    
54
/* FIXME:  These should be removed.  */
55
static TCGv cpu_F0s, cpu_F1s;
56
static TCGv_i64 cpu_F0d, cpu_F1d;
57

    
58
#include "gen-icount.h"
59

    
60
static 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.  */
67
void 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++) {
74
        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
75
                                offsetof(CPUUniCore32State, regs[i]), regnames[i]);
76
    }
77

    
78
#define GEN_HELPER 2
79
#include "helper.h"
80
}
81

    
82
static int num_temps;
83

    
84
/* Allocate a temporary variable.  */
85
static TCGv_i32 new_tmp(void)
86
{
87
    num_temps++;
88
    return tcg_temp_new_i32();
89
}
90

    
91
/* Release a temporary variable.  */
92
static void dead_tmp(TCGv tmp)
93
{
94
    tcg_temp_free(tmp);
95
    num_temps--;
96
}
97

    
98
static inline TCGv load_cpu_offset(int offset)
99
{
100
    TCGv tmp = new_tmp();
101
    tcg_gen_ld_i32(tmp, cpu_env, offset);
102
    return tmp;
103
}
104

    
105
#define load_cpu_field(name) load_cpu_offset(offsetof(CPUUniCore32State, name))
106

    
107
static inline void store_cpu_offset(TCGv var, int offset)
108
{
109
    tcg_gen_st_i32(var, cpu_env, offset);
110
    dead_tmp(var);
111
}
112

    
113
#define store_cpu_field(var, name) \
114
    store_cpu_offset(var, offsetof(CPUUniCore32State, name))
115

    
116
/* Set a variable to the value of a CPU register.  */
117
static void load_reg_var(DisasContext *s, TCGv var, int reg)
118
{
119
    if (reg == 31) {
120
        uint32_t addr;
121
        /* normaly, since we updated PC */
122
        addr = (long)s->pc;
123
        tcg_gen_movi_i32(var, addr);
124
    } else {
125
        tcg_gen_mov_i32(var, cpu_R[reg]);
126
    }
127
}
128

    
129
/* Create a new temporary and set it to the value of a CPU register.  */
130
static inline TCGv load_reg(DisasContext *s, int reg)
131
{
132
    TCGv tmp = new_tmp();
133
    load_reg_var(s, tmp, reg);
134
    return tmp;
135
}
136

    
137
/* Set a CPU register.  The source must be a temporary and will be
138
   marked as dead.  */
139
static void store_reg(DisasContext *s, int reg, TCGv var)
140
{
141
    if (reg == 31) {
142
        tcg_gen_andi_i32(var, var, ~3);
143
        s->is_jmp = DISAS_JUMP;
144
    }
145
    tcg_gen_mov_i32(cpu_R[reg], var);
146
    dead_tmp(var);
147
}
148

    
149
/* Value extensions.  */
150
#define gen_uxtb(var)           tcg_gen_ext8u_i32(var, var)
151
#define gen_uxth(var)           tcg_gen_ext16u_i32(var, var)
152
#define gen_sxtb(var)           tcg_gen_ext8s_i32(var, var)
153
#define gen_sxth(var)           tcg_gen_ext16s_i32(var, var)
154

    
155
#define UCOP_REG_M              (((insn) >>  0) & 0x1f)
156
#define UCOP_REG_N              (((insn) >> 19) & 0x1f)
157
#define UCOP_REG_D              (((insn) >> 14) & 0x1f)
158
#define UCOP_REG_S              (((insn) >>  9) & 0x1f)
159
#define UCOP_REG_LO             (((insn) >> 14) & 0x1f)
160
#define UCOP_REG_HI             (((insn) >>  9) & 0x1f)
161
#define UCOP_SH_OP              (((insn) >>  6) & 0x03)
162
#define UCOP_SH_IM              (((insn) >>  9) & 0x1f)
163
#define UCOP_OPCODES            (((insn) >> 25) & 0x0f)
164
#define UCOP_IMM_9              (((insn) >>  0) & 0x1ff)
165
#define UCOP_IMM10              (((insn) >>  0) & 0x3ff)
166
#define UCOP_IMM14              (((insn) >>  0) & 0x3fff)
167
#define UCOP_COND               (((insn) >> 25) & 0x0f)
168
#define UCOP_CMOV_COND          (((insn) >> 19) & 0x0f)
169
#define UCOP_CPNUM              (((insn) >> 10) & 0x0f)
170
#define UCOP_UCF64_FMT          (((insn) >> 24) & 0x03)
171
#define UCOP_UCF64_FUNC         (((insn) >>  6) & 0x0f)
172
#define UCOP_UCF64_COND         (((insn) >>  6) & 0x0f)
173

    
174
#define UCOP_SET(i)             ((insn) & (1 << (i)))
175
#define UCOP_SET_P              UCOP_SET(28)
176
#define UCOP_SET_U              UCOP_SET(27)
177
#define UCOP_SET_B              UCOP_SET(26)
178
#define UCOP_SET_W              UCOP_SET(25)
179
#define UCOP_SET_L              UCOP_SET(24)
180
#define UCOP_SET_S              UCOP_SET(24)
181

    
182
#define ILLEGAL         cpu_abort(env,                                  \
183
                        "Illegal UniCore32 instruction %x at line %d!", \
184
                        insn, __LINE__)
185

    
186
#ifndef CONFIG_USER_ONLY
187
static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s,
188
        uint32_t insn)
189
{
190
    TCGv tmp, tmp2, tmp3;
191
    if ((insn & 0xfe000000) == 0xe0000000) {
192
        tmp2 = new_tmp();
193
        tmp3 = new_tmp();
194
        tcg_gen_movi_i32(tmp2, UCOP_REG_N);
195
        tcg_gen_movi_i32(tmp3, UCOP_IMM10);
196
        if (UCOP_SET_L) {
197
            tmp = new_tmp();
198
            gen_helper_cp0_get(tmp, cpu_env, tmp2, tmp3);
199
            store_reg(s, UCOP_REG_D, tmp);
200
        } else {
201
            tmp = load_reg(s, UCOP_REG_D);
202
            gen_helper_cp0_set(cpu_env, tmp, tmp2, tmp3);
203
            dead_tmp(tmp);
204
        }
205
        dead_tmp(tmp2);
206
        dead_tmp(tmp3);
207
        return;
208
    }
209
    ILLEGAL;
210
}
211

    
212
static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s,
213
        uint32_t insn)
214
{
215
    TCGv tmp;
216

    
217
    if ((insn & 0xff003fff) == 0xe1000400) {
218
        /*
219
         * movc rd, pp.nn, #imm9
220
         *      rd: UCOP_REG_D
221
         *      nn: UCOP_REG_N (must be 0)
222
         *      imm9: 0
223
         */
224
        if (UCOP_REG_N == 0) {
225
            tmp = new_tmp();
226
            tcg_gen_movi_i32(tmp, 0);
227
            store_reg(s, UCOP_REG_D, tmp);
228
            return;
229
        } else {
230
            ILLEGAL;
231
        }
232
    }
233
    if ((insn & 0xff003fff) == 0xe0000401) {
234
        /*
235
         * movc pp.nn, rn, #imm9
236
         *      rn: UCOP_REG_D
237
         *      nn: UCOP_REG_N (must be 1)
238
         *      imm9: 1
239
         */
240
        if (UCOP_REG_N == 1) {
241
            tmp = load_reg(s, UCOP_REG_D);
242
            gen_helper_cp1_putc(tmp);
243
            dead_tmp(tmp);
244
            return;
245
        } else {
246
            ILLEGAL;
247
        }
248
    }
249
    ILLEGAL;
250
}
251
#endif
252

    
253
static inline void gen_set_asr(TCGv var, uint32_t mask)
254
{
255
    TCGv tmp_mask = tcg_const_i32(mask);
256
    gen_helper_asr_write(cpu_env, var, tmp_mask);
257
    tcg_temp_free_i32(tmp_mask);
258
}
259
/* Set NZCV flags from the high 4 bits of var.  */
260
#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV)
261

    
262
static void gen_exception(int excp)
263
{
264
    TCGv tmp = new_tmp();
265
    tcg_gen_movi_i32(tmp, excp);
266
    gen_helper_exception(cpu_env, tmp);
267
    dead_tmp(tmp);
268
}
269

    
270
/* FIXME: Most targets have native widening multiplication.
271
   It would be good to use that instead of a full wide multiply.  */
272
/* 32x32->64 multiply.  Marks inputs as dead.  */
273
static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
274
{
275
    TCGv_i64 tmp1 = tcg_temp_new_i64();
276
    TCGv_i64 tmp2 = tcg_temp_new_i64();
277

    
278
    tcg_gen_extu_i32_i64(tmp1, a);
279
    dead_tmp(a);
280
    tcg_gen_extu_i32_i64(tmp2, b);
281
    dead_tmp(b);
282
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
283
    tcg_temp_free_i64(tmp2);
284
    return tmp1;
285
}
286

    
287
static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
288
{
289
    TCGv_i64 tmp1 = tcg_temp_new_i64();
290
    TCGv_i64 tmp2 = tcg_temp_new_i64();
291

    
292
    tcg_gen_ext_i32_i64(tmp1, a);
293
    dead_tmp(a);
294
    tcg_gen_ext_i32_i64(tmp2, b);
295
    dead_tmp(b);
296
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
297
    tcg_temp_free_i64(tmp2);
298
    return tmp1;
299
}
300

    
301
#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, CF))
302

    
303
/* Set CF to the top bit of var.  */
304
static void gen_set_CF_bit31(TCGv var)
305
{
306
    TCGv tmp = new_tmp();
307
    tcg_gen_shri_i32(tmp, var, 31);
308
    gen_set_CF(tmp);
309
    dead_tmp(tmp);
310
}
311

    
312
/* Set N and Z flags from var.  */
313
static inline void gen_logic_CC(TCGv var)
314
{
315
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, NF));
316
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, ZF));
317
}
318

    
319
/* dest = T0 + T1 + CF. */
320
static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
321
{
322
    TCGv tmp;
323
    tcg_gen_add_i32(dest, t0, t1);
324
    tmp = load_cpu_field(CF);
325
    tcg_gen_add_i32(dest, dest, tmp);
326
    dead_tmp(tmp);
327
}
328

    
329
/* dest = T0 - T1 + CF - 1.  */
330
static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
331
{
332
    TCGv tmp;
333
    tcg_gen_sub_i32(dest, t0, t1);
334
    tmp = load_cpu_field(CF);
335
    tcg_gen_add_i32(dest, dest, tmp);
336
    tcg_gen_subi_i32(dest, dest, 1);
337
    dead_tmp(tmp);
338
}
339

    
340
static void shifter_out_im(TCGv var, int shift)
341
{
342
    TCGv tmp = new_tmp();
343
    if (shift == 0) {
344
        tcg_gen_andi_i32(tmp, var, 1);
345
    } else {
346
        tcg_gen_shri_i32(tmp, var, shift);
347
        if (shift != 31) {
348
            tcg_gen_andi_i32(tmp, tmp, 1);
349
        }
350
    }
351
    gen_set_CF(tmp);
352
    dead_tmp(tmp);
353
}
354

    
355
/* Shift by immediate.  Includes special handling for shift == 0.  */
356
static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift,
357
        int flags)
358
{
359
    switch (shiftop) {
360
    case 0: /* LSL */
361
        if (shift != 0) {
362
            if (flags) {
363
                shifter_out_im(var, 32 - shift);
364
            }
365
            tcg_gen_shli_i32(var, var, shift);
366
        }
367
        break;
368
    case 1: /* LSR */
369
        if (shift == 0) {
370
            if (flags) {
371
                tcg_gen_shri_i32(var, var, 31);
372
                gen_set_CF(var);
373
            }
374
            tcg_gen_movi_i32(var, 0);
375
        } else {
376
            if (flags) {
377
                shifter_out_im(var, shift - 1);
378
            }
379
            tcg_gen_shri_i32(var, var, shift);
380
        }
381
        break;
382
    case 2: /* ASR */
383
        if (shift == 0) {
384
            shift = 32;
385
        }
386
        if (flags) {
387
            shifter_out_im(var, shift - 1);
388
        }
389
        if (shift == 32) {
390
            shift = 31;
391
        }
392
        tcg_gen_sari_i32(var, var, shift);
393
        break;
394
    case 3: /* ROR/RRX */
395
        if (shift != 0) {
396
            if (flags) {
397
                shifter_out_im(var, shift - 1);
398
            }
399
            tcg_gen_rotri_i32(var, var, shift); break;
400
        } else {
401
            TCGv tmp = load_cpu_field(CF);
402
            if (flags) {
403
                shifter_out_im(var, 0);
404
            }
405
            tcg_gen_shri_i32(var, var, 1);
406
            tcg_gen_shli_i32(tmp, tmp, 31);
407
            tcg_gen_or_i32(var, var, tmp);
408
            dead_tmp(tmp);
409
        }
410
    }
411
};
412

    
413
static inline void gen_uc32_shift_reg(TCGv var, int shiftop,
414
                                     TCGv shift, int flags)
415
{
416
    if (flags) {
417
        switch (shiftop) {
418
        case 0:
419
            gen_helper_shl_cc(var, cpu_env, var, shift);
420
            break;
421
        case 1:
422
            gen_helper_shr_cc(var, cpu_env, var, shift);
423
            break;
424
        case 2:
425
            gen_helper_sar_cc(var, cpu_env, var, shift);
426
            break;
427
        case 3:
428
            gen_helper_ror_cc(var, cpu_env, var, shift);
429
            break;
430
        }
431
    } else {
432
        switch (shiftop) {
433
        case 0:
434
            gen_helper_shl(var, var, shift);
435
            break;
436
        case 1:
437
            gen_helper_shr(var, var, shift);
438
            break;
439
        case 2:
440
            gen_helper_sar(var, var, shift);
441
            break;
442
        case 3:
443
            tcg_gen_andi_i32(shift, shift, 0x1f);
444
            tcg_gen_rotr_i32(var, var, shift);
445
            break;
446
        }
447
    }
448
    dead_tmp(shift);
449
}
450

    
451
static void gen_test_cc(int cc, int label)
452
{
453
    TCGv tmp;
454
    TCGv tmp2;
455
    int inv;
456

    
457
    switch (cc) {
458
    case 0: /* eq: Z */
459
        tmp = load_cpu_field(ZF);
460
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
461
        break;
462
    case 1: /* ne: !Z */
463
        tmp = load_cpu_field(ZF);
464
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
465
        break;
466
    case 2: /* cs: C */
467
        tmp = load_cpu_field(CF);
468
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
469
        break;
470
    case 3: /* cc: !C */
471
        tmp = load_cpu_field(CF);
472
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
473
        break;
474
    case 4: /* mi: N */
475
        tmp = load_cpu_field(NF);
476
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
477
        break;
478
    case 5: /* pl: !N */
479
        tmp = load_cpu_field(NF);
480
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
481
        break;
482
    case 6: /* vs: V */
483
        tmp = load_cpu_field(VF);
484
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
485
        break;
486
    case 7: /* vc: !V */
487
        tmp = load_cpu_field(VF);
488
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
489
        break;
490
    case 8: /* hi: C && !Z */
491
        inv = gen_new_label();
492
        tmp = load_cpu_field(CF);
493
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
494
        dead_tmp(tmp);
495
        tmp = load_cpu_field(ZF);
496
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
497
        gen_set_label(inv);
498
        break;
499
    case 9: /* ls: !C || Z */
500
        tmp = load_cpu_field(CF);
501
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
502
        dead_tmp(tmp);
503
        tmp = load_cpu_field(ZF);
504
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
505
        break;
506
    case 10: /* ge: N == V -> N ^ V == 0 */
507
        tmp = load_cpu_field(VF);
508
        tmp2 = load_cpu_field(NF);
509
        tcg_gen_xor_i32(tmp, tmp, tmp2);
510
        dead_tmp(tmp2);
511
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
512
        break;
513
    case 11: /* lt: N != V -> N ^ V != 0 */
514
        tmp = load_cpu_field(VF);
515
        tmp2 = load_cpu_field(NF);
516
        tcg_gen_xor_i32(tmp, tmp, tmp2);
517
        dead_tmp(tmp2);
518
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
519
        break;
520
    case 12: /* gt: !Z && N == V */
521
        inv = gen_new_label();
522
        tmp = load_cpu_field(ZF);
523
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
524
        dead_tmp(tmp);
525
        tmp = load_cpu_field(VF);
526
        tmp2 = load_cpu_field(NF);
527
        tcg_gen_xor_i32(tmp, tmp, tmp2);
528
        dead_tmp(tmp2);
529
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
530
        gen_set_label(inv);
531
        break;
532
    case 13: /* le: Z || N != V */
533
        tmp = load_cpu_field(ZF);
534
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
535
        dead_tmp(tmp);
536
        tmp = load_cpu_field(VF);
537
        tmp2 = load_cpu_field(NF);
538
        tcg_gen_xor_i32(tmp, tmp, tmp2);
539
        dead_tmp(tmp2);
540
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
541
        break;
542
    default:
543
        fprintf(stderr, "Bad condition code 0x%x\n", cc);
544
        abort();
545
    }
546
    dead_tmp(tmp);
547
}
548

    
549
static const uint8_t table_logic_cc[16] = {
550
    1, /* and */    1, /* xor */    0, /* sub */    0, /* rsb */
551
    0, /* add */    0, /* adc */    0, /* sbc */    0, /* rsc */
552
    1, /* andl */   1, /* xorl */   0, /* cmp */    0, /* cmn */
553
    1, /* orr */    1, /* mov */    1, /* bic */    1, /* mvn */
554
};
555

    
556
/* Set PC state from an immediate address.  */
557
static inline void gen_bx_im(DisasContext *s, uint32_t addr)
558
{
559
    s->is_jmp = DISAS_UPDATE;
560
    tcg_gen_movi_i32(cpu_R[31], addr & ~3);
561
}
562

    
563
/* Set PC state from var.  var is marked as dead.  */
564
static inline void gen_bx(DisasContext *s, TCGv var)
565
{
566
    s->is_jmp = DISAS_UPDATE;
567
    tcg_gen_andi_i32(cpu_R[31], var, ~3);
568
    dead_tmp(var);
569
}
570

    
571
static inline void store_reg_bx(DisasContext *s, int reg, TCGv var)
572
{
573
    store_reg(s, reg, var);
574
}
575

    
576
static inline TCGv gen_ld8s(TCGv addr, int index)
577
{
578
    TCGv tmp = new_tmp();
579
    tcg_gen_qemu_ld8s(tmp, addr, index);
580
    return tmp;
581
}
582

    
583
static inline TCGv gen_ld8u(TCGv addr, int index)
584
{
585
    TCGv tmp = new_tmp();
586
    tcg_gen_qemu_ld8u(tmp, addr, index);
587
    return tmp;
588
}
589

    
590
static inline TCGv gen_ld16s(TCGv addr, int index)
591
{
592
    TCGv tmp = new_tmp();
593
    tcg_gen_qemu_ld16s(tmp, addr, index);
594
    return tmp;
595
}
596

    
597
static inline TCGv gen_ld16u(TCGv addr, int index)
598
{
599
    TCGv tmp = new_tmp();
600
    tcg_gen_qemu_ld16u(tmp, addr, index);
601
    return tmp;
602
}
603

    
604
static inline TCGv gen_ld32(TCGv addr, int index)
605
{
606
    TCGv tmp = new_tmp();
607
    tcg_gen_qemu_ld32u(tmp, addr, index);
608
    return tmp;
609
}
610

    
611
static inline TCGv_i64 gen_ld64(TCGv addr, int index)
612
{
613
    TCGv_i64 tmp = tcg_temp_new_i64();
614
    tcg_gen_qemu_ld64(tmp, addr, index);
615
    return tmp;
616
}
617

    
618
static inline void gen_st8(TCGv val, TCGv addr, int index)
619
{
620
    tcg_gen_qemu_st8(val, addr, index);
621
    dead_tmp(val);
622
}
623

    
624
static inline void gen_st16(TCGv val, TCGv addr, int index)
625
{
626
    tcg_gen_qemu_st16(val, addr, index);
627
    dead_tmp(val);
628
}
629

    
630
static inline void gen_st32(TCGv val, TCGv addr, int index)
631
{
632
    tcg_gen_qemu_st32(val, addr, index);
633
    dead_tmp(val);
634
}
635

    
636
static inline void gen_st64(TCGv_i64 val, TCGv addr, int index)
637
{
638
    tcg_gen_qemu_st64(val, addr, index);
639
    tcg_temp_free_i64(val);
640
}
641

    
642
static inline void gen_set_pc_im(uint32_t val)
643
{
644
    tcg_gen_movi_i32(cpu_R[31], val);
645
}
646

    
647
/* Force a TB lookup after an instruction that changes the CPU state.  */
648
static inline void gen_lookup_tb(DisasContext *s)
649
{
650
    tcg_gen_movi_i32(cpu_R[31], s->pc & ~1);
651
    s->is_jmp = DISAS_UPDATE;
652
}
653

    
654
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
655
        TCGv var)
656
{
657
    int val;
658
    TCGv offset;
659

    
660
    if (UCOP_SET(29)) {
661
        /* immediate */
662
        val = UCOP_IMM14;
663
        if (!UCOP_SET_U) {
664
            val = -val;
665
        }
666
        if (val != 0) {
667
            tcg_gen_addi_i32(var, var, val);
668
        }
669
    } else {
670
        /* shift/register */
671
        offset = load_reg(s, UCOP_REG_M);
672
        gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0);
673
        if (!UCOP_SET_U) {
674
            tcg_gen_sub_i32(var, var, offset);
675
        } else {
676
            tcg_gen_add_i32(var, var, offset);
677
        }
678
        dead_tmp(offset);
679
    }
680
}
681

    
682
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
683
        TCGv var)
684
{
685
    int val;
686
    TCGv offset;
687

    
688
    if (UCOP_SET(26)) {
689
        /* immediate */
690
        val = (insn & 0x1f) | ((insn >> 4) & 0x3e0);
691
        if (!UCOP_SET_U) {
692
            val = -val;
693
        }
694
        if (val != 0) {
695
            tcg_gen_addi_i32(var, var, val);
696
        }
697
    } else {
698
        /* register */
699
        offset = load_reg(s, UCOP_REG_M);
700
        if (!UCOP_SET_U) {
701
            tcg_gen_sub_i32(var, var, offset);
702
        } else {
703
            tcg_gen_add_i32(var, var, offset);
704
        }
705
        dead_tmp(offset);
706
    }
707
}
708

    
709
static inline long ucf64_reg_offset(int reg)
710
{
711
    if (reg & 1) {
712
        return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1])
713
          + offsetof(CPU_DoubleU, l.upper);
714
    } else {
715
        return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1])
716
          + offsetof(CPU_DoubleU, l.lower);
717
    }
718
}
719

    
720
#define ucf64_gen_ld32(reg)      load_cpu_offset(ucf64_reg_offset(reg))
721
#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg))
722

    
723
/* UniCore-F64 single load/store I_offset */
724
static void do_ucf64_ldst_i(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
725
{
726
    int offset;
727
    TCGv tmp;
728
    TCGv addr;
729

    
730
    addr = load_reg(s, UCOP_REG_N);
731
    if (!UCOP_SET_P && !UCOP_SET_W) {
732
        ILLEGAL;
733
    }
734

    
735
    if (UCOP_SET_P) {
736
        offset = UCOP_IMM10 << 2;
737
        if (!UCOP_SET_U) {
738
            offset = -offset;
739
        }
740
        if (offset != 0) {
741
            tcg_gen_addi_i32(addr, addr, offset);
742
        }
743
    }
744

    
745
    if (UCOP_SET_L) { /* load */
746
        tmp = gen_ld32(addr, IS_USER(s));
747
        ucf64_gen_st32(tmp, UCOP_REG_D);
748
    } else { /* store */
749
        tmp = ucf64_gen_ld32(UCOP_REG_D);
750
        gen_st32(tmp, addr, IS_USER(s));
751
    }
752

    
753
    if (!UCOP_SET_P) {
754
        offset = UCOP_IMM10 << 2;
755
        if (!UCOP_SET_U) {
756
            offset = -offset;
757
        }
758
        if (offset != 0) {
759
            tcg_gen_addi_i32(addr, addr, offset);
760
        }
761
    }
762
    if (UCOP_SET_W) {
763
        store_reg(s, UCOP_REG_N, addr);
764
    } else {
765
        dead_tmp(addr);
766
    }
767
}
768

    
769
/* UniCore-F64 load/store multiple words */
770
static void do_ucf64_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
771
{
772
    unsigned int i;
773
    int j, n, freg;
774
    TCGv tmp;
775
    TCGv addr;
776

    
777
    if (UCOP_REG_D != 0) {
778
        ILLEGAL;
779
    }
780
    if (UCOP_REG_N == 31) {
781
        ILLEGAL;
782
    }
783
    if ((insn << 24) == 0) {
784
        ILLEGAL;
785
    }
786

    
787
    addr = load_reg(s, UCOP_REG_N);
788

    
789
    n = 0;
790
    for (i = 0; i < 8; i++) {
791
        if (UCOP_SET(i)) {
792
            n++;
793
        }
794
    }
795

    
796
    if (UCOP_SET_U) {
797
        if (UCOP_SET_P) { /* pre increment */
798
            tcg_gen_addi_i32(addr, addr, 4);
799
        } /* unnecessary to do anything when post increment */
800
    } else {
801
        if (UCOP_SET_P) { /* pre decrement */
802
            tcg_gen_addi_i32(addr, addr, -(n * 4));
803
        } else { /* post decrement */
804
            if (n != 1) {
805
                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
806
            }
807
        }
808
    }
809

    
810
    freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */
811

    
812
    for (i = 0, j = 0; i < 8; i++, freg++) {
813
        if (!UCOP_SET(i)) {
814
            continue;
815
        }
816

    
817
        if (UCOP_SET_L) { /* load */
818
            tmp = gen_ld32(addr, IS_USER(s));
819
            ucf64_gen_st32(tmp, freg);
820
        } else { /* store */
821
            tmp = ucf64_gen_ld32(freg);
822
            gen_st32(tmp, addr, IS_USER(s));
823
        }
824

    
825
        j++;
826
        /* unnecessary to add after the last transfer */
827
        if (j != n) {
828
            tcg_gen_addi_i32(addr, addr, 4);
829
        }
830
    }
831

    
832
    if (UCOP_SET_W) { /* write back */
833
        if (UCOP_SET_U) {
834
            if (!UCOP_SET_P) { /* post increment */
835
                tcg_gen_addi_i32(addr, addr, 4);
836
            } /* unnecessary to do anything when pre increment */
837
        } else {
838
            if (UCOP_SET_P) {
839
                /* pre decrement */
840
                if (n != 1) {
841
                    tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
842
                }
843
            } else {
844
                /* post decrement */
845
                tcg_gen_addi_i32(addr, addr, -(n * 4));
846
            }
847
        }
848
        store_reg(s, UCOP_REG_N, addr);
849
    } else {
850
        dead_tmp(addr);
851
    }
852
}
853

    
854
/* UniCore-F64 mrc/mcr */
855
static void do_ucf64_trans(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
856
{
857
    TCGv tmp;
858

    
859
    if ((insn & 0xfe0003ff) == 0xe2000000) {
860
        /* control register */
861
        if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) {
862
            ILLEGAL;
863
        }
864
        if (UCOP_SET(24)) {
865
            /* CFF */
866
            tmp = new_tmp();
867
            gen_helper_ucf64_get_fpscr(tmp, cpu_env);
868
            store_reg(s, UCOP_REG_D, tmp);
869
        } else {
870
            /* CTF */
871
            tmp = load_reg(s, UCOP_REG_D);
872
            gen_helper_ucf64_set_fpscr(cpu_env, tmp);
873
            dead_tmp(tmp);
874
            gen_lookup_tb(s);
875
        }
876
        return;
877
    }
878
    if ((insn & 0xfe0003ff) == 0xe0000000) {
879
        /* general register */
880
        if (UCOP_REG_D == 31) {
881
            ILLEGAL;
882
        }
883
        if (UCOP_SET(24)) { /* MFF */
884
            tmp = ucf64_gen_ld32(UCOP_REG_N);
885
            store_reg(s, UCOP_REG_D, tmp);
886
        } else { /* MTF */
887
            tmp = load_reg(s, UCOP_REG_D);
888
            ucf64_gen_st32(tmp, UCOP_REG_N);
889
        }
890
        return;
891
    }
892
    if ((insn & 0xfb000000) == 0xe9000000) {
893
        /* MFFC */
894
        if (UCOP_REG_D != 31) {
895
            ILLEGAL;
896
        }
897
        if (UCOP_UCF64_COND & 0x8) {
898
            ILLEGAL;
899
        }
900

    
901
        tmp = new_tmp();
902
        tcg_gen_movi_i32(tmp, UCOP_UCF64_COND);
903
        if (UCOP_SET(26)) {
904
            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
905
            tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
906
            gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env);
907
        } else {
908
            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
909
            tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
910
            gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env);
911
        }
912
        dead_tmp(tmp);
913
        return;
914
    }
915
    ILLEGAL;
916
}
917

    
918
/* UniCore-F64 convert instructions */
919
static void do_ucf64_fcvt(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
920
{
921
    if (UCOP_UCF64_FMT == 3) {
922
        ILLEGAL;
923
    }
924
    if (UCOP_REG_N != 0) {
925
        ILLEGAL;
926
    }
927
    switch (UCOP_UCF64_FUNC) {
928
    case 0: /* cvt.s */
929
        switch (UCOP_UCF64_FMT) {
930
        case 1 /* d */:
931
            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
932
            gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env);
933
            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
934
            break;
935
        case 2 /* w */:
936
            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
937
            gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env);
938
            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
939
            break;
940
        default /* s */:
941
            ILLEGAL;
942
            break;
943
        }
944
        break;
945
    case 1: /* cvt.d */
946
        switch (UCOP_UCF64_FMT) {
947
        case 0 /* s */:
948
            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
949
            gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env);
950
            tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
951
            break;
952
        case 2 /* w */:
953
            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
954
            gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env);
955
            tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
956
            break;
957
        default /* d */:
958
            ILLEGAL;
959
            break;
960
        }
961
        break;
962
    case 4: /* cvt.w */
963
        switch (UCOP_UCF64_FMT) {
964
        case 0 /* s */:
965
            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
966
            gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env);
967
            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
968
            break;
969
        case 1 /* d */:
970
            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
971
            gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env);
972
            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
973
            break;
974
    default /* w */:
975
            ILLEGAL;
976
            break;
977
        }
978
        break;
979
    default:
980
        ILLEGAL;
981
    }
982
}
983

    
984
/* UniCore-F64 compare instructions */
985
static void do_ucf64_fcmp(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
986
{
987
    if (UCOP_SET(25)) {
988
        ILLEGAL;
989
    }
990
    if (UCOP_REG_D != 0) {
991
        ILLEGAL;
992
    }
993

    
994
    ILLEGAL; /* TODO */
995
    if (UCOP_SET(24)) {
996
        tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
997
        tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
998
        /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */
999
    } else {
1000
        tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
1001
        tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
1002
        /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */
1003
    }
1004
}
1005

    
1006
#define gen_helper_ucf64_movs(x, y)      do { } while (0)
1007
#define gen_helper_ucf64_movd(x, y)      do { } while (0)
1008

    
1009
#define UCF64_OP1(name)    do {                           \
1010
        if (UCOP_REG_N != 0) {                            \
1011
            ILLEGAL;                                      \
1012
        }                                                 \
1013
        switch (UCOP_UCF64_FMT) {                         \
1014
        case 0 /* s */:                                   \
1015
            tcg_gen_ld_i32(cpu_F0s, cpu_env,              \
1016
                           ucf64_reg_offset(UCOP_REG_M)); \
1017
            gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \
1018
            tcg_gen_st_i32(cpu_F0s, cpu_env,              \
1019
                           ucf64_reg_offset(UCOP_REG_D)); \
1020
            break;                                        \
1021
        case 1 /* d */:                                   \
1022
            tcg_gen_ld_i64(cpu_F0d, cpu_env,              \
1023
                           ucf64_reg_offset(UCOP_REG_M)); \
1024
            gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \
1025
            tcg_gen_st_i64(cpu_F0d, cpu_env,              \
1026
                           ucf64_reg_offset(UCOP_REG_D)); \
1027
            break;                                        \
1028
        case 2 /* w */:                                   \
1029
            ILLEGAL;                                      \
1030
            break;                                        \
1031
        }                                                 \
1032
    } while (0)
1033

    
1034
#define UCF64_OP2(name)    do {                           \
1035
        switch (UCOP_UCF64_FMT) {                         \
1036
        case 0 /* s */:                                   \
1037
            tcg_gen_ld_i32(cpu_F0s, cpu_env,              \
1038
                           ucf64_reg_offset(UCOP_REG_N)); \
1039
            tcg_gen_ld_i32(cpu_F1s, cpu_env,              \
1040
                           ucf64_reg_offset(UCOP_REG_M)); \
1041
            gen_helper_ucf64_##name##s(cpu_F0s,           \
1042
                           cpu_F0s, cpu_F1s, cpu_env);    \
1043
            tcg_gen_st_i32(cpu_F0s, cpu_env,              \
1044
                           ucf64_reg_offset(UCOP_REG_D)); \
1045
            break;                                        \
1046
        case 1 /* d */:                                   \
1047
            tcg_gen_ld_i64(cpu_F0d, cpu_env,              \
1048
                           ucf64_reg_offset(UCOP_REG_N)); \
1049
            tcg_gen_ld_i64(cpu_F1d, cpu_env,              \
1050
                           ucf64_reg_offset(UCOP_REG_M)); \
1051
            gen_helper_ucf64_##name##d(cpu_F0d,           \
1052
                           cpu_F0d, cpu_F1d, cpu_env);    \
1053
            tcg_gen_st_i64(cpu_F0d, cpu_env,              \
1054
                           ucf64_reg_offset(UCOP_REG_D)); \
1055
            break;                                        \
1056
        case 2 /* w */:                                   \
1057
            ILLEGAL;                                      \
1058
            break;                                        \
1059
        }                                                 \
1060
    } while (0)
1061

    
1062
/* UniCore-F64 data processing */
1063
static void do_ucf64_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1064
{
1065
    if (UCOP_UCF64_FMT == 3) {
1066
        ILLEGAL;
1067
    }
1068
    switch (UCOP_UCF64_FUNC) {
1069
    case 0: /* add */
1070
        UCF64_OP2(add);
1071
        break;
1072
    case 1: /* sub */
1073
        UCF64_OP2(sub);
1074
        break;
1075
    case 2: /* mul */
1076
        UCF64_OP2(mul);
1077
        break;
1078
    case 4: /* div */
1079
        UCF64_OP2(div);
1080
        break;
1081
    case 5: /* abs */
1082
        UCF64_OP1(abs);
1083
        break;
1084
    case 6: /* mov */
1085
        UCF64_OP1(mov);
1086
        break;
1087
    case 7: /* neg */
1088
        UCF64_OP1(neg);
1089
        break;
1090
    default:
1091
        ILLEGAL;
1092
    }
1093
}
1094

    
1095
/* Disassemble an F64 instruction */
1096
static void disas_ucf64_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1097
{
1098
    if (!UCOP_SET(29)) {
1099
        if (UCOP_SET(26)) {
1100
            do_ucf64_ldst_m(env, s, insn);
1101
        } else {
1102
            do_ucf64_ldst_i(env, s, insn);
1103
        }
1104
    } else {
1105
        if (UCOP_SET(5)) {
1106
            switch ((insn >> 26) & 0x3) {
1107
            case 0:
1108
                do_ucf64_datap(env, s, insn);
1109
                break;
1110
            case 1:
1111
                ILLEGAL;
1112
                break;
1113
            case 2:
1114
                do_ucf64_fcvt(env, s, insn);
1115
                break;
1116
            case 3:
1117
                do_ucf64_fcmp(env, s, insn);
1118
                break;
1119
            }
1120
        } else {
1121
            do_ucf64_trans(env, s, insn);
1122
        }
1123
    }
1124
}
1125

    
1126
static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
1127
{
1128
    TranslationBlock *tb;
1129

    
1130
    tb = s->tb;
1131
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
1132
        tcg_gen_goto_tb(n);
1133
        gen_set_pc_im(dest);
1134
        tcg_gen_exit_tb((tcg_target_long)tb + n);
1135
    } else {
1136
        gen_set_pc_im(dest);
1137
        tcg_gen_exit_tb(0);
1138
    }
1139
}
1140

    
1141
static inline void gen_jmp(DisasContext *s, uint32_t dest)
1142
{
1143
    if (unlikely(s->singlestep_enabled)) {
1144
        /* An indirect jump so that we still trigger the debug exception.  */
1145
        gen_bx_im(s, dest);
1146
    } else {
1147
        gen_goto_tb(s, 0, dest);
1148
        s->is_jmp = DISAS_TB_JUMP;
1149
    }
1150
}
1151

    
1152
static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
1153
{
1154
    if (x) {
1155
        tcg_gen_sari_i32(t0, t0, 16);
1156
    } else {
1157
        gen_sxth(t0);
1158
    }
1159
    if (y) {
1160
        tcg_gen_sari_i32(t1, t1, 16);
1161
    } else {
1162
        gen_sxth(t1);
1163
    }
1164
    tcg_gen_mul_i32(t0, t0, t1);
1165
}
1166

    
1167
/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
1168
static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0)
1169
{
1170
    TCGv tmp;
1171
    if (bsr) {
1172
        /* ??? This is also undefined in system mode.  */
1173
        if (IS_USER(s)) {
1174
            return 1;
1175
        }
1176

    
1177
        tmp = load_cpu_field(bsr);
1178
        tcg_gen_andi_i32(tmp, tmp, ~mask);
1179
        tcg_gen_andi_i32(t0, t0, mask);
1180
        tcg_gen_or_i32(tmp, tmp, t0);
1181
        store_cpu_field(tmp, bsr);
1182
    } else {
1183
        gen_set_asr(t0, mask);
1184
    }
1185
    dead_tmp(t0);
1186
    gen_lookup_tb(s);
1187
    return 0;
1188
}
1189

    
1190
/* Generate an old-style exception return. Marks pc as dead. */
1191
static void gen_exception_return(DisasContext *s, TCGv pc)
1192
{
1193
    TCGv tmp;
1194
    store_reg(s, 31, pc);
1195
    tmp = load_cpu_field(bsr);
1196
    gen_set_asr(tmp, 0xffffffff);
1197
    dead_tmp(tmp);
1198
    s->is_jmp = DISAS_UPDATE;
1199
}
1200

    
1201
static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s,
1202
        uint32_t insn)
1203
{
1204
    switch (UCOP_CPNUM) {
1205
#ifndef CONFIG_USER_ONLY
1206
    case 0:
1207
        disas_cp0_insn(env, s, insn);
1208
        break;
1209
    case 1:
1210
        disas_ocd_insn(env, s, insn);
1211
        break;
1212
#endif
1213
    case 2:
1214
        disas_ucf64_insn(env, s, insn);
1215
        break;
1216
    default:
1217
        /* Unknown coprocessor. */
1218
        cpu_abort(env, "Unknown coprocessor!");
1219
    }
1220
}
1221

    
1222

    
1223
/* Store a 64-bit value to a register pair.  Clobbers val.  */
1224
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
1225
{
1226
    TCGv tmp;
1227
    tmp = new_tmp();
1228
    tcg_gen_trunc_i64_i32(tmp, val);
1229
    store_reg(s, rlow, tmp);
1230
    tmp = new_tmp();
1231
    tcg_gen_shri_i64(val, val, 32);
1232
    tcg_gen_trunc_i64_i32(tmp, val);
1233
    store_reg(s, rhigh, tmp);
1234
}
1235

    
1236
/* load and add a 64-bit value from a register pair.  */
1237
static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
1238
{
1239
    TCGv_i64 tmp;
1240
    TCGv tmpl;
1241
    TCGv tmph;
1242

    
1243
    /* Load 64-bit value rd:rn.  */
1244
    tmpl = load_reg(s, rlow);
1245
    tmph = load_reg(s, rhigh);
1246
    tmp = tcg_temp_new_i64();
1247
    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
1248
    dead_tmp(tmpl);
1249
    dead_tmp(tmph);
1250
    tcg_gen_add_i64(val, val, tmp);
1251
    tcg_temp_free_i64(tmp);
1252
}
1253

    
1254
/* data processing instructions */
1255
static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1256
{
1257
    TCGv tmp;
1258
    TCGv tmp2;
1259
    int logic_cc;
1260

    
1261
    if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) {
1262
        if (UCOP_SET(23)) { /* CMOV instructions */
1263
            if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) {
1264
                ILLEGAL;
1265
            }
1266
            /* if not always execute, we generate a conditional jump to
1267
               next instruction */
1268
            s->condlabel = gen_new_label();
1269
            gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel);
1270
            s->condjmp = 1;
1271
        }
1272
    }
1273

    
1274
    logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24);
1275

    
1276
    if (UCOP_SET(29)) {
1277
        unsigned int val;
1278
        /* immediate operand */
1279
        val = UCOP_IMM_9;
1280
        if (UCOP_SH_IM) {
1281
            val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
1282
        }
1283
        tmp2 = new_tmp();
1284
        tcg_gen_movi_i32(tmp2, val);
1285
        if (logic_cc && UCOP_SH_IM) {
1286
            gen_set_CF_bit31(tmp2);
1287
        }
1288
   } else {
1289
        /* register */
1290
        tmp2 = load_reg(s, UCOP_REG_M);
1291
        if (UCOP_SET(5)) {
1292
            tmp = load_reg(s, UCOP_REG_S);
1293
            gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc);
1294
        } else {
1295
            gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc);
1296
        }
1297
    }
1298

    
1299
    if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
1300
        tmp = load_reg(s, UCOP_REG_N);
1301
    } else {
1302
        TCGV_UNUSED(tmp);
1303
    }
1304

    
1305
    switch (UCOP_OPCODES) {
1306
    case 0x00:
1307
        tcg_gen_and_i32(tmp, tmp, tmp2);
1308
        if (logic_cc) {
1309
            gen_logic_CC(tmp);
1310
        }
1311
        store_reg_bx(s, UCOP_REG_D, tmp);
1312
        break;
1313
    case 0x01:
1314
        tcg_gen_xor_i32(tmp, tmp, tmp2);
1315
        if (logic_cc) {
1316
            gen_logic_CC(tmp);
1317
        }
1318
        store_reg_bx(s, UCOP_REG_D, tmp);
1319
        break;
1320
    case 0x02:
1321
        if (UCOP_SET_S && UCOP_REG_D == 31) {
1322
            /* SUBS r31, ... is used for exception return.  */
1323
            if (IS_USER(s)) {
1324
                ILLEGAL;
1325
            }
1326
            gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
1327
            gen_exception_return(s, tmp);
1328
        } else {
1329
            if (UCOP_SET_S) {
1330
                gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
1331
            } else {
1332
                tcg_gen_sub_i32(tmp, tmp, tmp2);
1333
            }
1334
            store_reg_bx(s, UCOP_REG_D, tmp);
1335
        }
1336
        break;
1337
    case 0x03:
1338
        if (UCOP_SET_S) {
1339
            gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp);
1340
        } else {
1341
            tcg_gen_sub_i32(tmp, tmp2, tmp);
1342
        }
1343
        store_reg_bx(s, UCOP_REG_D, tmp);
1344
        break;
1345
    case 0x04:
1346
        if (UCOP_SET_S) {
1347
            gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
1348
        } else {
1349
            tcg_gen_add_i32(tmp, tmp, tmp2);
1350
        }
1351
        store_reg_bx(s, UCOP_REG_D, tmp);
1352
        break;
1353
    case 0x05:
1354
        if (UCOP_SET_S) {
1355
            gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2);
1356
        } else {
1357
            gen_add_carry(tmp, tmp, tmp2);
1358
        }
1359
        store_reg_bx(s, UCOP_REG_D, tmp);
1360
        break;
1361
    case 0x06:
1362
        if (UCOP_SET_S) {
1363
            gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2);
1364
        } else {
1365
            gen_sub_carry(tmp, tmp, tmp2);
1366
        }
1367
        store_reg_bx(s, UCOP_REG_D, tmp);
1368
        break;
1369
    case 0x07:
1370
        if (UCOP_SET_S) {
1371
            gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp);
1372
        } else {
1373
            gen_sub_carry(tmp, tmp2, tmp);
1374
        }
1375
        store_reg_bx(s, UCOP_REG_D, tmp);
1376
        break;
1377
    case 0x08:
1378
        if (UCOP_SET_S) {
1379
            tcg_gen_and_i32(tmp, tmp, tmp2);
1380
            gen_logic_CC(tmp);
1381
        }
1382
        dead_tmp(tmp);
1383
        break;
1384
    case 0x09:
1385
        if (UCOP_SET_S) {
1386
            tcg_gen_xor_i32(tmp, tmp, tmp2);
1387
            gen_logic_CC(tmp);
1388
        }
1389
        dead_tmp(tmp);
1390
        break;
1391
    case 0x0a:
1392
        if (UCOP_SET_S) {
1393
            gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
1394
        }
1395
        dead_tmp(tmp);
1396
        break;
1397
    case 0x0b:
1398
        if (UCOP_SET_S) {
1399
            gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
1400
        }
1401
        dead_tmp(tmp);
1402
        break;
1403
    case 0x0c:
1404
        tcg_gen_or_i32(tmp, tmp, tmp2);
1405
        if (logic_cc) {
1406
            gen_logic_CC(tmp);
1407
        }
1408
        store_reg_bx(s, UCOP_REG_D, tmp);
1409
        break;
1410
    case 0x0d:
1411
        if (logic_cc && UCOP_REG_D == 31) {
1412
            /* MOVS r31, ... is used for exception return.  */
1413
            if (IS_USER(s)) {
1414
                ILLEGAL;
1415
            }
1416
            gen_exception_return(s, tmp2);
1417
        } else {
1418
            if (logic_cc) {
1419
                gen_logic_CC(tmp2);
1420
            }
1421
            store_reg_bx(s, UCOP_REG_D, tmp2);
1422
        }
1423
        break;
1424
    case 0x0e:
1425
        tcg_gen_andc_i32(tmp, tmp, tmp2);
1426
        if (logic_cc) {
1427
            gen_logic_CC(tmp);
1428
        }
1429
        store_reg_bx(s, UCOP_REG_D, tmp);
1430
        break;
1431
    default:
1432
    case 0x0f:
1433
        tcg_gen_not_i32(tmp2, tmp2);
1434
        if (logic_cc) {
1435
            gen_logic_CC(tmp2);
1436
        }
1437
        store_reg_bx(s, UCOP_REG_D, tmp2);
1438
        break;
1439
    }
1440
    if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
1441
        dead_tmp(tmp2);
1442
    }
1443
}
1444

    
1445
/* multiply */
1446
static void do_mult(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1447
{
1448
    TCGv tmp;
1449
    TCGv tmp2;
1450
    TCGv_i64 tmp64;
1451

    
1452
    if (UCOP_SET(27)) {
1453
        /* 64 bit mul */
1454
        tmp = load_reg(s, UCOP_REG_M);
1455
        tmp2 = load_reg(s, UCOP_REG_N);
1456
        if (UCOP_SET(26)) {
1457
            tmp64 = gen_muls_i64_i32(tmp, tmp2);
1458
        } else {
1459
            tmp64 = gen_mulu_i64_i32(tmp, tmp2);
1460
        }
1461
        if (UCOP_SET(25)) { /* mult accumulate */
1462
            gen_addq(s, tmp64, UCOP_REG_LO, UCOP_REG_HI);
1463
        }
1464
        gen_storeq_reg(s, UCOP_REG_LO, UCOP_REG_HI, tmp64);
1465
        tcg_temp_free_i64(tmp64);
1466
    } else {
1467
        /* 32 bit mul */
1468
        tmp = load_reg(s, UCOP_REG_M);
1469
        tmp2 = load_reg(s, UCOP_REG_N);
1470
        tcg_gen_mul_i32(tmp, tmp, tmp2);
1471
        dead_tmp(tmp2);
1472
        if (UCOP_SET(25)) {
1473
            /* Add */
1474
            tmp2 = load_reg(s, UCOP_REG_S);
1475
            tcg_gen_add_i32(tmp, tmp, tmp2);
1476
            dead_tmp(tmp2);
1477
        }
1478
        if (UCOP_SET_S) {
1479
            gen_logic_CC(tmp);
1480
        }
1481
        store_reg(s, UCOP_REG_D, tmp);
1482
    }
1483
}
1484

    
1485
/* miscellaneous instructions */
1486
static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1487
{
1488
    unsigned int val;
1489
    TCGv tmp;
1490

    
1491
    if ((insn & 0xffffffe0) == 0x10ffc120) {
1492
        /* Trivial implementation equivalent to bx.  */
1493
        tmp = load_reg(s, UCOP_REG_M);
1494
        gen_bx(s, tmp);
1495
        return;
1496
    }
1497

    
1498
    if ((insn & 0xfbffc000) == 0x30ffc000) {
1499
        /* PSR = immediate */
1500
        val = UCOP_IMM_9;
1501
        if (UCOP_SH_IM) {
1502
            val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
1503
        }
1504
        tmp = new_tmp();
1505
        tcg_gen_movi_i32(tmp, val);
1506
        if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
1507
            ILLEGAL;
1508
        }
1509
        return;
1510
    }
1511

    
1512
    if ((insn & 0xfbffffe0) == 0x12ffc020) {
1513
        /* PSR.flag = reg */
1514
        tmp = load_reg(s, UCOP_REG_M);
1515
        if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) {
1516
            ILLEGAL;
1517
        }
1518
        return;
1519
    }
1520

    
1521
    if ((insn & 0xfbffffe0) == 0x10ffc020) {
1522
        /* PSR = reg */
1523
        tmp = load_reg(s, UCOP_REG_M);
1524
        if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
1525
            ILLEGAL;
1526
        }
1527
        return;
1528
    }
1529

    
1530
    if ((insn & 0xfbf83fff) == 0x10f80000) {
1531
        /* reg = PSR */
1532
        if (UCOP_SET_B) {
1533
            if (IS_USER(s)) {
1534
                ILLEGAL;
1535
            }
1536
            tmp = load_cpu_field(bsr);
1537
        } else {
1538
            tmp = new_tmp();
1539
            gen_helper_asr_read(tmp, cpu_env);
1540
        }
1541
        store_reg(s, UCOP_REG_D, tmp);
1542
        return;
1543
    }
1544

    
1545
    if ((insn & 0xfbf83fe0) == 0x12f80120) {
1546
        /* clz */
1547
        tmp = load_reg(s, UCOP_REG_M);
1548
        if (UCOP_SET(26)) {
1549
            gen_helper_clo(tmp, tmp);
1550
        } else {
1551
            gen_helper_clz(tmp, tmp);
1552
        }
1553
        store_reg(s, UCOP_REG_D, tmp);
1554
        return;
1555
    }
1556

    
1557
    /* otherwise */
1558
    ILLEGAL;
1559
}
1560

    
1561
/* load/store I_offset and R_offset */
1562
static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1563
{
1564
    unsigned int mmu_idx;
1565
    TCGv tmp;
1566
    TCGv tmp2;
1567

    
1568
    tmp2 = load_reg(s, UCOP_REG_N);
1569
    mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
1570

    
1571
    /* immediate */
1572
    if (UCOP_SET_P) {
1573
        gen_add_data_offset(s, insn, tmp2);
1574
    }
1575

    
1576
    if (UCOP_SET_L) {
1577
        /* load */
1578
        if (UCOP_SET_B) {
1579
            tmp = gen_ld8u(tmp2, mmu_idx);
1580
        } else {
1581
            tmp = gen_ld32(tmp2, mmu_idx);
1582
        }
1583
    } else {
1584
        /* store */
1585
        tmp = load_reg(s, UCOP_REG_D);
1586
        if (UCOP_SET_B) {
1587
            gen_st8(tmp, tmp2, mmu_idx);
1588
        } else {
1589
            gen_st32(tmp, tmp2, mmu_idx);
1590
        }
1591
    }
1592
    if (!UCOP_SET_P) {
1593
        gen_add_data_offset(s, insn, tmp2);
1594
        store_reg(s, UCOP_REG_N, tmp2);
1595
    } else if (UCOP_SET_W) {
1596
        store_reg(s, UCOP_REG_N, tmp2);
1597
    } else {
1598
        dead_tmp(tmp2);
1599
    }
1600
    if (UCOP_SET_L) {
1601
        /* Complete the load.  */
1602
        if (UCOP_REG_D == 31) {
1603
            gen_bx(s, tmp);
1604
        } else {
1605
            store_reg(s, UCOP_REG_D, tmp);
1606
        }
1607
    }
1608
}
1609

    
1610
/* SWP instruction */
1611
static void do_swap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1612
{
1613
    TCGv addr;
1614
    TCGv tmp;
1615
    TCGv tmp2;
1616

    
1617
    if ((insn & 0xff003fe0) != 0x40000120) {
1618
        ILLEGAL;
1619
    }
1620

    
1621
    /* ??? This is not really atomic.  However we know
1622
       we never have multiple CPUs running in parallel,
1623
       so it is good enough.  */
1624
    addr = load_reg(s, UCOP_REG_N);
1625
    tmp = load_reg(s, UCOP_REG_M);
1626
    if (UCOP_SET_B) {
1627
        tmp2 = gen_ld8u(addr, IS_USER(s));
1628
        gen_st8(tmp, addr, IS_USER(s));
1629
    } else {
1630
        tmp2 = gen_ld32(addr, IS_USER(s));
1631
        gen_st32(tmp, addr, IS_USER(s));
1632
    }
1633
    dead_tmp(addr);
1634
    store_reg(s, UCOP_REG_D, tmp2);
1635
}
1636

    
1637
/* load/store hw/sb */
1638
static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1639
{
1640
    TCGv addr;
1641
    TCGv tmp;
1642

    
1643
    if (UCOP_SH_OP == 0) {
1644
        do_swap(env, s, insn);
1645
        return;
1646
    }
1647

    
1648
    addr = load_reg(s, UCOP_REG_N);
1649
    if (UCOP_SET_P) {
1650
        gen_add_datah_offset(s, insn, addr);
1651
    }
1652

    
1653
    if (UCOP_SET_L) { /* load */
1654
        switch (UCOP_SH_OP) {
1655
        case 1:
1656
            tmp = gen_ld16u(addr, IS_USER(s));
1657
            break;
1658
        case 2:
1659
            tmp = gen_ld8s(addr, IS_USER(s));
1660
            break;
1661
        default: /* see do_swap */
1662
        case 3:
1663
            tmp = gen_ld16s(addr, IS_USER(s));
1664
            break;
1665
        }
1666
    } else { /* store */
1667
        if (UCOP_SH_OP != 1) {
1668
            ILLEGAL;
1669
        }
1670
        tmp = load_reg(s, UCOP_REG_D);
1671
        gen_st16(tmp, addr, IS_USER(s));
1672
    }
1673
    /* Perform base writeback before the loaded value to
1674
       ensure correct behavior with overlapping index registers. */
1675
    if (!UCOP_SET_P) {
1676
        gen_add_datah_offset(s, insn, addr);
1677
        store_reg(s, UCOP_REG_N, addr);
1678
    } else if (UCOP_SET_W) {
1679
        store_reg(s, UCOP_REG_N, addr);
1680
    } else {
1681
        dead_tmp(addr);
1682
    }
1683
    if (UCOP_SET_L) {
1684
        /* Complete the load.  */
1685
        store_reg(s, UCOP_REG_D, tmp);
1686
    }
1687
}
1688

    
1689
/* load/store multiple words */
1690
static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1691
{
1692
    unsigned int val, i, mmu_idx;
1693
    int j, n, reg, user, loaded_base;
1694
    TCGv tmp;
1695
    TCGv tmp2;
1696
    TCGv addr;
1697
    TCGv loaded_var;
1698

    
1699
    if (UCOP_SET(7)) {
1700
        ILLEGAL;
1701
    }
1702
    /* XXX: store correct base if write back */
1703
    user = 0;
1704
    if (UCOP_SET_B) { /* S bit in instruction table */
1705
        if (IS_USER(s)) {
1706
            ILLEGAL; /* only usable in supervisor mode */
1707
        }
1708
        if (UCOP_SET(18) == 0) { /* pc reg */
1709
            user = 1;
1710
        }
1711
    }
1712

    
1713
    mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
1714
    addr = load_reg(s, UCOP_REG_N);
1715

    
1716
    /* compute total size */
1717
    loaded_base = 0;
1718
    TCGV_UNUSED(loaded_var);
1719
    n = 0;
1720
    for (i = 0; i < 6; i++) {
1721
        if (UCOP_SET(i)) {
1722
            n++;
1723
        }
1724
    }
1725
    for (i = 9; i < 19; i++) {
1726
        if (UCOP_SET(i)) {
1727
            n++;
1728
        }
1729
    }
1730
    /* XXX: test invalid n == 0 case ? */
1731
    if (UCOP_SET_U) {
1732
        if (UCOP_SET_P) {
1733
            /* pre increment */
1734
            tcg_gen_addi_i32(addr, addr, 4);
1735
        } else {
1736
            /* post increment */
1737
        }
1738
    } else {
1739
        if (UCOP_SET_P) {
1740
            /* pre decrement */
1741
            tcg_gen_addi_i32(addr, addr, -(n * 4));
1742
        } else {
1743
            /* post decrement */
1744
            if (n != 1) {
1745
                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
1746
            }
1747
        }
1748
    }
1749

    
1750
    j = 0;
1751
    reg = UCOP_SET(6) ? 16 : 0;
1752
    for (i = 0; i < 19; i++, reg++) {
1753
        if (i == 6) {
1754
            i = i + 3;
1755
        }
1756
        if (UCOP_SET(i)) {
1757
            if (UCOP_SET_L) { /* load */
1758
                tmp = gen_ld32(addr, mmu_idx);
1759
                if (reg == 31) {
1760
                    gen_bx(s, tmp);
1761
                } else if (user) {
1762
                    tmp2 = tcg_const_i32(reg);
1763
                    gen_helper_set_user_reg(cpu_env, tmp2, tmp);
1764
                    tcg_temp_free_i32(tmp2);
1765
                    dead_tmp(tmp);
1766
                } else if (reg == UCOP_REG_N) {
1767
                    loaded_var = tmp;
1768
                    loaded_base = 1;
1769
                } else {
1770
                    store_reg(s, reg, tmp);
1771
                }
1772
            } else { /* store */
1773
                if (reg == 31) {
1774
                    /* special case: r31 = PC + 4 */
1775
                    val = (long)s->pc;
1776
                    tmp = new_tmp();
1777
                    tcg_gen_movi_i32(tmp, val);
1778
                } else if (user) {
1779
                    tmp = new_tmp();
1780
                    tmp2 = tcg_const_i32(reg);
1781
                    gen_helper_get_user_reg(tmp, cpu_env, tmp2);
1782
                    tcg_temp_free_i32(tmp2);
1783
                } else {
1784
                    tmp = load_reg(s, reg);
1785
                }
1786
                gen_st32(tmp, addr, mmu_idx);
1787
            }
1788
            j++;
1789
            /* no need to add after the last transfer */
1790
            if (j != n) {
1791
                tcg_gen_addi_i32(addr, addr, 4);
1792
            }
1793
        }
1794
    }
1795
    if (UCOP_SET_W) { /* write back */
1796
        if (UCOP_SET_U) {
1797
            if (UCOP_SET_P) {
1798
                /* pre increment */
1799
            } else {
1800
                /* post increment */
1801
                tcg_gen_addi_i32(addr, addr, 4);
1802
            }
1803
        } else {
1804
            if (UCOP_SET_P) {
1805
                /* pre decrement */
1806
                if (n != 1) {
1807
                    tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
1808
                }
1809
            } else {
1810
                /* post decrement */
1811
                tcg_gen_addi_i32(addr, addr, -(n * 4));
1812
            }
1813
        }
1814
        store_reg(s, UCOP_REG_N, addr);
1815
    } else {
1816
        dead_tmp(addr);
1817
    }
1818
    if (loaded_base) {
1819
        store_reg(s, UCOP_REG_N, loaded_var);
1820
    }
1821
    if (UCOP_SET_B && !user) {
1822
        /* Restore ASR from BSR.  */
1823
        tmp = load_cpu_field(bsr);
1824
        gen_set_asr(tmp, 0xffffffff);
1825
        dead_tmp(tmp);
1826
        s->is_jmp = DISAS_UPDATE;
1827
    }
1828
}
1829

    
1830
/* branch (and link) */
1831
static void do_branch(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
1832
{
1833
    unsigned int val;
1834
    int32_t offset;
1835
    TCGv tmp;
1836

    
1837
    if (UCOP_COND == 0xf) {
1838
        ILLEGAL;
1839
    }
1840

    
1841
    if (UCOP_COND != 0xe) {
1842
        /* if not always execute, we generate a conditional jump to
1843
           next instruction */
1844
        s->condlabel = gen_new_label();
1845
        gen_test_cc(UCOP_COND ^ 1, s->condlabel);
1846
        s->condjmp = 1;
1847
    }
1848

    
1849
    val = (int32_t)s->pc;
1850
    if (UCOP_SET_L) {
1851
        tmp = new_tmp();
1852
        tcg_gen_movi_i32(tmp, val);
1853
        store_reg(s, 30, tmp);
1854
    }
1855
    offset = (((int32_t)insn << 8) >> 8);
1856
    val += (offset << 2); /* unicore is pc+4 */
1857
    gen_jmp(s, val);
1858
}
1859

    
1860
static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
1861
{
1862
    unsigned int insn;
1863

    
1864
    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
1865
        tcg_gen_debug_insn_start(s->pc);
1866
    }
1867

    
1868
    insn = cpu_ldl_code(env, s->pc);
1869
    s->pc += 4;
1870

    
1871
    /* UniCore instructions class:
1872
     * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx
1873
     * AAA  : see switch case
1874
     * BBBB : opcodes or cond or PUBW
1875
     * C    : S OR L
1876
     * D    : 8
1877
     * E    : 5
1878
     */
1879
    switch (insn >> 29) {
1880
    case 0x0:
1881
        if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) {
1882
            do_mult(env, s, insn);
1883
            break;
1884
        }
1885

    
1886
        if (UCOP_SET(8)) {
1887
            do_misc(env, s, insn);
1888
            break;
1889
        }
1890
    case 0x1:
1891
        if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) {
1892
            do_misc(env, s, insn);
1893
            break;
1894
        }
1895
        do_datap(env, s, insn);
1896
        break;
1897

    
1898
    case 0x2:
1899
        if (UCOP_SET(8) && UCOP_SET(5)) {
1900
            do_ldst_hwsb(env, s, insn);
1901
            break;
1902
        }
1903
        if (UCOP_SET(8) || UCOP_SET(5)) {
1904
            ILLEGAL;
1905
        }
1906
    case 0x3:
1907
        do_ldst_ir(env, s, insn);
1908
        break;
1909

    
1910
    case 0x4:
1911
        if (UCOP_SET(8)) {
1912
            ILLEGAL; /* extended instructions */
1913
        }
1914
        do_ldst_m(env, s, insn);
1915
        break;
1916
    case 0x5:
1917
        do_branch(env, s, insn);
1918
        break;
1919
    case 0x6:
1920
        /* Coprocessor.  */
1921
        disas_coproc_insn(env, s, insn);
1922
        break;
1923
    case 0x7:
1924
        if (!UCOP_SET(28)) {
1925
            disas_coproc_insn(env, s, insn);
1926
            break;
1927
        }
1928
        if ((insn & 0xff000000) == 0xff000000) { /* syscall */
1929
            gen_set_pc_im(s->pc);
1930
            s->is_jmp = DISAS_SYSCALL;
1931
            break;
1932
        }
1933
        ILLEGAL;
1934
    }
1935
}
1936

    
1937
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
1938
   basic block 'tb'. If search_pc is TRUE, also generate PC
1939
   information for each intermediate instruction. */
1940
static inline void gen_intermediate_code_internal(CPUUniCore32State *env,
1941
        TranslationBlock *tb, int search_pc)
1942
{
1943
    DisasContext dc1, *dc = &dc1;
1944
    CPUBreakpoint *bp;
1945
    uint16_t *gen_opc_end;
1946
    int j, lj;
1947
    target_ulong pc_start;
1948
    uint32_t next_page_start;
1949
    int num_insns;
1950
    int max_insns;
1951

    
1952
    /* generate intermediate code */
1953
    num_temps = 0;
1954

    
1955
    pc_start = tb->pc;
1956

    
1957
    dc->tb = tb;
1958

    
1959
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1960

    
1961
    dc->is_jmp = DISAS_NEXT;
1962
    dc->pc = pc_start;
1963
    dc->singlestep_enabled = env->singlestep_enabled;
1964
    dc->condjmp = 0;
1965
    cpu_F0s = tcg_temp_new_i32();
1966
    cpu_F1s = tcg_temp_new_i32();
1967
    cpu_F0d = tcg_temp_new_i64();
1968
    cpu_F1d = tcg_temp_new_i64();
1969
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
1970
    lj = -1;
1971
    num_insns = 0;
1972
    max_insns = tb->cflags & CF_COUNT_MASK;
1973
    if (max_insns == 0) {
1974
        max_insns = CF_COUNT_MASK;
1975
    }
1976

    
1977
#ifndef CONFIG_USER_ONLY
1978
    if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) {
1979
        dc->user = 1;
1980
    } else {
1981
        dc->user = 0;
1982
    }
1983
#endif
1984

    
1985
    gen_icount_start();
1986
    do {
1987
        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
1988
            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
1989
                if (bp->pc == dc->pc) {
1990
                    gen_set_pc_im(dc->pc);
1991
                    gen_exception(EXCP_DEBUG);
1992
                    dc->is_jmp = DISAS_JUMP;
1993
                    /* Advance PC so that clearing the breakpoint will
1994
                       invalidate this TB.  */
1995
                    dc->pc += 2; /* FIXME */
1996
                    goto done_generating;
1997
                    break;
1998
                }
1999
            }
2000
        }
2001
        if (search_pc) {
2002
            j = gen_opc_ptr - gen_opc_buf;
2003
            if (lj < j) {
2004
                lj++;
2005
                while (lj < j) {
2006
                    gen_opc_instr_start[lj++] = 0;
2007
                }
2008
            }
2009
            gen_opc_pc[lj] = dc->pc;
2010
            gen_opc_instr_start[lj] = 1;
2011
            gen_opc_icount[lj] = num_insns;
2012
        }
2013

    
2014
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
2015
            gen_io_start();
2016
        }
2017

    
2018
        disas_uc32_insn(env, dc);
2019

    
2020
        if (num_temps) {
2021
            fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
2022
            num_temps = 0;
2023
        }
2024

    
2025
        if (dc->condjmp && !dc->is_jmp) {
2026
            gen_set_label(dc->condlabel);
2027
            dc->condjmp = 0;
2028
        }
2029
        /* Translation stops when a conditional branch is encountered.
2030
         * Otherwise the subsequent code could get translated several times.
2031
         * Also stop translation when a page boundary is reached.  This
2032
         * ensures prefetch aborts occur at the right place.  */
2033
        num_insns++;
2034
    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
2035
             !env->singlestep_enabled &&
2036
             !singlestep &&
2037
             dc->pc < next_page_start &&
2038
             num_insns < max_insns);
2039

    
2040
    if (tb->cflags & CF_LAST_IO) {
2041
        if (dc->condjmp) {
2042
            /* FIXME:  This can theoretically happen with self-modifying
2043
               code.  */
2044
            cpu_abort(env, "IO on conditional branch instruction");
2045
        }
2046
        gen_io_end();
2047
    }
2048

    
2049
    /* At this stage dc->condjmp will only be set when the skipped
2050
       instruction was a conditional branch or trap, and the PC has
2051
       already been written.  */
2052
    if (unlikely(env->singlestep_enabled)) {
2053
        /* Make sure the pc is updated, and raise a debug exception.  */
2054
        if (dc->condjmp) {
2055
            if (dc->is_jmp == DISAS_SYSCALL) {
2056
                gen_exception(UC32_EXCP_PRIV);
2057
            } else {
2058
                gen_exception(EXCP_DEBUG);
2059
            }
2060
            gen_set_label(dc->condlabel);
2061
        }
2062
        if (dc->condjmp || !dc->is_jmp) {
2063
            gen_set_pc_im(dc->pc);
2064
            dc->condjmp = 0;
2065
        }
2066
        if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) {
2067
            gen_exception(UC32_EXCP_PRIV);
2068
        } else {
2069
            gen_exception(EXCP_DEBUG);
2070
        }
2071
    } else {
2072
        /* While branches must always occur at the end of an IT block,
2073
           there are a few other things that can cause us to terminate
2074
           the TB in the middel of an IT block:
2075
            - Exception generating instructions (bkpt, swi, undefined).
2076
            - Page boundaries.
2077
            - Hardware watchpoints.
2078
           Hardware breakpoints have already been handled and skip this code.
2079
         */
2080
        switch (dc->is_jmp) {
2081
        case DISAS_NEXT:
2082
            gen_goto_tb(dc, 1, dc->pc);
2083
            break;
2084
        default:
2085
        case DISAS_JUMP:
2086
        case DISAS_UPDATE:
2087
            /* indicate that the hash table must be used to find the next TB */
2088
            tcg_gen_exit_tb(0);
2089
            break;
2090
        case DISAS_TB_JUMP:
2091
            /* nothing more to generate */
2092
            break;
2093
        case DISAS_SYSCALL:
2094
            gen_exception(UC32_EXCP_PRIV);
2095
            break;
2096
        }
2097
        if (dc->condjmp) {
2098
            gen_set_label(dc->condlabel);
2099
            gen_goto_tb(dc, 1, dc->pc);
2100
            dc->condjmp = 0;
2101
        }
2102
    }
2103

    
2104
done_generating:
2105
    gen_icount_end(tb, num_insns);
2106
    *gen_opc_ptr = INDEX_op_end;
2107

    
2108
#ifdef DEBUG_DISAS
2109
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
2110
        qemu_log("----------------\n");
2111
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
2112
        log_target_disas(pc_start, dc->pc - pc_start, 0);
2113
        qemu_log("\n");
2114
    }
2115
#endif
2116
    if (search_pc) {
2117
        j = gen_opc_ptr - gen_opc_buf;
2118
        lj++;
2119
        while (lj <= j) {
2120
            gen_opc_instr_start[lj++] = 0;
2121
        }
2122
    } else {
2123
        tb->size = dc->pc - pc_start;
2124
        tb->icount = num_insns;
2125
    }
2126
}
2127

    
2128
void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
2129
{
2130
    gen_intermediate_code_internal(env, tb, 0);
2131
}
2132

    
2133
void gen_intermediate_code_pc(CPUUniCore32State *env, TranslationBlock *tb)
2134
{
2135
    gen_intermediate_code_internal(env, tb, 1);
2136
}
2137

    
2138
static const char *cpu_mode_names[16] = {
2139
    "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP",
2140
    "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR"
2141
};
2142

    
2143
#undef UCF64_DUMP_STATE
2144
#ifdef UCF64_DUMP_STATE
2145
static void cpu_dump_state_ucf64(CPUUniCore32State *env, FILE *f,
2146
        fprintf_function cpu_fprintf, int flags)
2147
{
2148
    int i;
2149
    union {
2150
        uint32_t i;
2151
        float s;
2152
    } s0, s1;
2153
    CPU_DoubleU d;
2154
    /* ??? This assumes float64 and double have the same layout.
2155
       Oh well, it's only debug dumps.  */
2156
    union {
2157
        float64 f64;
2158
        double d;
2159
    } d0;
2160

    
2161
    for (i = 0; i < 16; i++) {
2162
        d.d = env->ucf64.regs[i];
2163
        s0.i = d.l.lower;
2164
        s1.i = d.l.upper;
2165
        d0.f64 = d.d;
2166
        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)",
2167
                    i * 2, (int)s0.i, s0.s,
2168
                    i * 2 + 1, (int)s1.i, s1.s);
2169
        cpu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n",
2170
                    i, (uint64_t)d0.f64, d0.d);
2171
    }
2172
    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
2173
}
2174
#else
2175
#define cpu_dump_state_ucf64(env, file, pr, flags)      do { } while (0)
2176
#endif
2177

    
2178
void cpu_dump_state(CPUUniCore32State *env, FILE *f,
2179
        fprintf_function cpu_fprintf, int flags)
2180
{
2181
    int i;
2182
    uint32_t psr;
2183

    
2184
    for (i = 0; i < 32; i++) {
2185
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2186
        if ((i % 4) == 3) {
2187
            cpu_fprintf(f, "\n");
2188
        } else {
2189
            cpu_fprintf(f, " ");
2190
        }
2191
    }
2192
    psr = cpu_asr_read(env);
2193
    cpu_fprintf(f, "PSR=%08x %c%c%c%c %s\n",
2194
                psr,
2195
                psr & (1 << 31) ? 'N' : '-',
2196
                psr & (1 << 30) ? 'Z' : '-',
2197
                psr & (1 << 29) ? 'C' : '-',
2198
                psr & (1 << 28) ? 'V' : '-',
2199
                cpu_mode_names[psr & 0xf]);
2200

    
2201
    cpu_dump_state_ucf64(env, f, cpu_fprintf, flags);
2202
}
2203

    
2204
void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb, int pc_pos)
2205
{
2206
    env->regs[31] = gen_opc_pc[pc_pos];
2207
}