translate.c 93.1 KB
Newer Older
1 2 3
/*
 *  CRIS emulation for qemu: main translation routines.
 *
4
 *  Copyright (c) 2008 AXIS Communications AB
5 6 7 8 9 10 11 12 13 14 15 16 17
 *  Written by Edgar E. Iglesias.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 20
 */

edgar_igl's avatar
edgar_igl committed
21 22
/*
 * FIXME:
23
 * The condition code translation is in need of attention.
edgar_igl's avatar
edgar_igl committed
24 25
 */

26
#include "cpu.h"
27
#include "disas/disas.h"
bellard's avatar
bellard committed
28
#include "tcg-op.h"
29
#include "helper.h"
30
#include "mmu.h"
31 32
#include "crisv32-decode.h"

pbrook's avatar
pbrook committed
33 34 35
#define GEN_HELPER 1
#include "helper.h"

36 37
#define DISAS_CRIS 0
#if DISAS_CRIS
38
#  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
39
#else
40
#  define LOG_DIS(...) do { } while (0)
41 42
#endif

edgar_igl's avatar
edgar_igl committed
43
#define D(x)
44 45 46
#define BUG() (gen_BUG(dc, __FILE__, __LINE__))
#define BUG_ON(x) ({if (x) BUG();})

47 48
#define DISAS_SWI 5

49 50 51 52 53 54 55 56 57
/* Used by the decoder.  */
#define EXTRACT_FIELD(src, start, end) \
            (((src) >> start) & ((1 << (end - start + 1)) - 1))

#define CC_MASK_NZ 0xc
#define CC_MASK_NZV 0xe
#define CC_MASK_NZVC 0xf
#define CC_MASK_RNZV 0x10e

pbrook's avatar
pbrook committed
58
static TCGv_ptr cpu_env;
edgar_igl's avatar
edgar_igl committed
59 60 61 62 63 64 65 66 67 68 69 70 71
static TCGv cpu_R[16];
static TCGv cpu_PR[16];
static TCGv cc_x;
static TCGv cc_src;
static TCGv cc_dest;
static TCGv cc_result;
static TCGv cc_op;
static TCGv cc_size;
static TCGv cc_mask;

static TCGv env_btaken;
static TCGv env_btarget;
static TCGv env_pc;
edgar_igl's avatar
edgar_igl committed
72

73
#include "exec/gen-icount.h"
pbrook's avatar
pbrook committed
74

75 76
/* This is the state at translation time.  */
typedef struct DisasContext {
77 78
    CPUCRISState *env;
    target_ulong pc, ppc;
79

80
    /* Decoder.  */
81
        unsigned int (*decoder)(CPUCRISState *env, struct DisasContext *dc);
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
    uint32_t ir;
    uint32_t opcode;
    unsigned int op1;
    unsigned int op2;
    unsigned int zsize, zzsize;
    unsigned int mode;
    unsigned int postinc;

    unsigned int size;
    unsigned int src;
    unsigned int dst;
    unsigned int cond;

    int update_cc;
    int cc_op;
    int cc_size;
    uint32_t cc_mask;

    int cc_size_uptodate; /* -1 invalid or last written value.  */

    int cc_x_uptodate;  /* 1 - ccs, 2 - known | X_FLAG. 0 not uptodate.  */
    int flags_uptodate; /* Wether or not $ccs is uptodate.  */
    int flagx_known; /* Wether or not flags_x has the x flag known at
                translation time.  */
    int flags_x;

    int clear_x; /* Clear x after this insn?  */
    int clear_prefix; /* Clear prefix after this insn?  */
    int clear_locked_irq; /* Clear the irq lockout.  */
    int cpustate_changed;
    unsigned int tb_flags; /* tb dependent flags.  */
    int is_jmp;
114

115 116 117 118
#define JMP_NOJMP     0
#define JMP_DIRECT    1
#define JMP_DIRECT_CC 2
#define JMP_INDIRECT  3
119 120
    int jmp; /* 0=nojmp, 1=direct, 2=indirect.  */
    uint32_t jmp_pc;
edgar_igl's avatar
edgar_igl committed
121

122
    int delayed_branch;
123

124 125
    struct TranslationBlock *tb;
    int singlestep_enabled;
126 127
} DisasContext;

128
static void gen_BUG(DisasContext *dc, const char *file, int line)
129
{
130 131 132
    printf("BUG: pc=%x %s %d\n", dc->pc, file, line);
    qemu_log("BUG: pc=%x %s %d\n", dc->pc, file, line);
    cpu_abort(dc->env, "%s:%d\n", file, line);
133 134
}

edgar_igl's avatar
edgar_igl committed
135
static const char *regnames[] =
edgar_igl's avatar
edgar_igl committed
136
{
137 138 139 140
    "$r0", "$r1", "$r2", "$r3",
    "$r4", "$r5", "$r6", "$r7",
    "$r8", "$r9", "$r10", "$r11",
    "$r12", "$r13", "$sp", "$acr",
edgar_igl's avatar
edgar_igl committed
141
};
edgar_igl's avatar
edgar_igl committed
142
static const char *pregnames[] =
edgar_igl's avatar
edgar_igl committed
143
{
144 145 146 147
    "$bz", "$vr", "$pid", "$srs",
    "$wz", "$exs", "$eda", "$mof",
    "$dz", "$ebp", "$erp", "$srp",
    "$nrp", "$ccs", "$usp", "$spc",
edgar_igl's avatar
edgar_igl committed
148 149
};

150
/* We need this table to handle preg-moves with implicit width.  */
edgar_igl's avatar
edgar_igl committed
151
static int preg_sizes[] = {
152 153 154 155 156 157 158 159
    1, /* bz.  */
    1, /* vr.  */
    4, /* pid.  */
    1, /* srs.  */
    2, /* wz.  */
    4, 4, 4,
    4, 4, 4, 4,
    4, 4, 4, 4,
160 161 162
};

#define t_gen_mov_TN_env(tn, member) \
163
 _t_gen_mov_TN_env((tn), offsetof(CPUCRISState, member))
164
#define t_gen_mov_env_TN(member, tn) \
165
 _t_gen_mov_env_TN(offsetof(CPUCRISState, member), (tn))
166

edgar_igl's avatar
edgar_igl committed
167 168
static inline void t_gen_mov_TN_reg(TCGv tn, int r)
{
169 170 171 172
    if (r < 0 || r > 15) {
        fprintf(stderr, "wrong register read $r%d\n", r);
    }
    tcg_gen_mov_tl(tn, cpu_R[r]);
edgar_igl's avatar
edgar_igl committed
173 174 175
}
static inline void t_gen_mov_reg_TN(int r, TCGv tn)
{
176 177 178 179
    if (r < 0 || r > 15) {
        fprintf(stderr, "wrong register write $r%d\n", r);
    }
    tcg_gen_mov_tl(cpu_R[r], tn);
edgar_igl's avatar
edgar_igl committed
180
}
181 182 183

static inline void _t_gen_mov_TN_env(TCGv tn, int offset)
{
184 185 186 187
    if (offset > sizeof(CPUCRISState)) {
        fprintf(stderr, "wrong load from env from off=%d\n", offset);
    }
    tcg_gen_ld_tl(tn, cpu_env, offset);
188 189 190
}
static inline void _t_gen_mov_env_TN(int offset, TCGv tn)
{
191 192 193 194
    if (offset > sizeof(CPUCRISState)) {
        fprintf(stderr, "wrong store to env at off=%d\n", offset);
    }
    tcg_gen_st_tl(tn, cpu_env, offset);
195 196 197 198
}

static inline void t_gen_mov_TN_preg(TCGv tn, int r)
{
199 200 201 202 203 204 205 206 207 208
    if (r < 0 || r > 15) {
        fprintf(stderr, "wrong register read $p%d\n", r);
    }
    if (r == PR_BZ || r == PR_WZ || r == PR_DZ) {
        tcg_gen_mov_tl(tn, tcg_const_tl(0));
    } else if (r == PR_VR) {
        tcg_gen_mov_tl(tn, tcg_const_tl(32));
    } else {
        tcg_gen_mov_tl(tn, cpu_PR[r]);
    }
209
}
210
static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn)
211
{
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
    if (r < 0 || r > 15) {
        fprintf(stderr, "wrong register write $p%d\n", r);
    }
    if (r == PR_BZ || r == PR_WZ || r == PR_DZ) {
        return;
    } else if (r == PR_SRS) {
        tcg_gen_andi_tl(cpu_PR[r], tn, 3);
    } else {
        if (r == PR_PID) {
            gen_helper_tlb_flush_pid(cpu_env, tn);
        }
        if (dc->tb_flags & S_FLAG && r == PR_SPC) {
            gen_helper_spc_write(cpu_env, tn);
        } else if (r == PR_CCS) {
            dc->cpustate_changed = 1;
        }
        tcg_gen_mov_tl(cpu_PR[r], tn);
    }
230 231
}

232 233 234
/* Sign extend at translation time.  */
static int sign_extend(unsigned int val, unsigned int width)
{
235
    int sval;
236

237 238 239 240 241 242
    /* LSL.  */
    val <<= 31 - width;
    sval = val;
    /* ASR.  */
    sval >>= 31 - width;
    return sval;
243 244
}

245
static int cris_fetch(CPUCRISState *env, DisasContext *dc, uint32_t addr,
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
              unsigned int size, unsigned int sign)
{
    int r;

    switch (size) {
    case 4:
    {
        r = cpu_ldl_code(env, addr);
        break;
    }
    case 2:
    {
        if (sign) {
            r = cpu_ldsw_code(env, addr);
        } else {
            r = cpu_lduw_code(env, addr);
        }
        break;
    }
    case 1:
    {
        if (sign) {
            r = cpu_ldsb_code(env, addr);
        } else {
            r = cpu_ldub_code(env, addr);
        }
        break;
    }
    default:
        cpu_abort(dc->env, "Invalid fetch size %d\n", size);
        break;
    }
    return r;
279 280
}

281 282
static void cris_lock_irq(DisasContext *dc)
{
283 284
    dc->clear_locked_irq = 0;
    t_gen_mov_env_TN(locked_irq, tcg_const_tl(1));
285 286
}

edgar_igl's avatar
edgar_igl committed
287
static inline void t_gen_raise_exception(uint32_t index)
288
{
pbrook's avatar
pbrook committed
289
        TCGv_i32 tmp = tcg_const_i32(index);
290
        gen_helper_raise_exception(cpu_env, tmp);
pbrook's avatar
pbrook committed
291
        tcg_temp_free_i32(tmp);
292 293 294 295
}

static void t_gen_lsl(TCGv d, TCGv a, TCGv b)
{
296
    TCGv t0, t_31;
297

298 299 300
    t0 = tcg_temp_new();
    t_31 = tcg_const_tl(31);
    tcg_gen_shl_tl(d, a, b);
301

302 303 304 305 306 307
    tcg_gen_sub_tl(t0, t_31, b);
    tcg_gen_sar_tl(t0, t0, t_31);
    tcg_gen_and_tl(t0, t0, d);
    tcg_gen_xor_tl(d, d, t0);
    tcg_temp_free(t0);
    tcg_temp_free(t_31);
308 309 310 311
}

static void t_gen_lsr(TCGv d, TCGv a, TCGv b)
{
312
    TCGv t0, t_31;
313

314 315 316
    t0 = tcg_temp_new();
    t_31 = tcg_temp_new();
    tcg_gen_shr_tl(d, a, b);
317

318 319 320 321 322 323 324
    tcg_gen_movi_tl(t_31, 31);
    tcg_gen_sub_tl(t0, t_31, b);
    tcg_gen_sar_tl(t0, t0, t_31);
    tcg_gen_and_tl(t0, t0, d);
    tcg_gen_xor_tl(d, d, t0);
    tcg_temp_free(t0);
    tcg_temp_free(t_31);
325 326 327 328
}

static void t_gen_asr(TCGv d, TCGv a, TCGv b)
{
329
    TCGv t0, t_31;
330

331 332 333
    t0 = tcg_temp_new();
    t_31 = tcg_temp_new();
    tcg_gen_sar_tl(d, a, b);
334

335 336 337 338 339 340
    tcg_gen_movi_tl(t_31, 31);
    tcg_gen_sub_tl(t0, t_31, b);
    tcg_gen_sar_tl(t0, t0, t_31);
    tcg_gen_or_tl(d, d, t0);
    tcg_temp_free(t0);
    tcg_temp_free(t_31);
341 342
}

343
static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b)
344
{
345
    int l1;
346

347
    l1 = gen_new_label();
348

349 350 351 352 353 354 355 356 357
    /*
     * d <<= 1
     * if (d >= s)
     *    d -= s;
     */
    tcg_gen_shli_tl(d, a, 1);
    tcg_gen_brcond_tl(TCG_COND_LTU, d, b, l1);
    tcg_gen_sub_tl(d, d, b);
    gen_set_label(l1);
358 359
}

360 361
static void t_gen_cris_mstep(TCGv d, TCGv a, TCGv b, TCGv ccs)
{
362
    TCGv t;
363

364 365 366 367 368 369 370 371 372 373 374 375
    /*
     * d <<= 1
     * if (n)
     *    d += s;
     */
    t = tcg_temp_new();
    tcg_gen_shli_tl(d, a, 1);
    tcg_gen_shli_tl(t, ccs, 31 - 3);
    tcg_gen_sari_tl(t, t, 31);
    tcg_gen_and_tl(t, t, b);
    tcg_gen_add_tl(d, d, t);
    tcg_temp_free(t);
376 377
}

edgar_igl's avatar
edgar_igl committed
378 379 380
/* Extended arithmetics on CRIS.  */
static inline void t_gen_add_flag(TCGv d, int flag)
{
381
    TCGv c;
edgar_igl's avatar
edgar_igl committed
382

383 384 385 386 387 388 389 390 391
    c = tcg_temp_new();
    t_gen_mov_TN_preg(c, PR_CCS);
    /* Propagate carry into d.  */
    tcg_gen_andi_tl(c, c, 1 << flag);
    if (flag) {
        tcg_gen_shri_tl(c, c, flag);
    }
    tcg_gen_add_tl(d, d, c);
    tcg_temp_free(c);
edgar_igl's avatar
edgar_igl committed
392 393
}

394
static inline void t_gen_addx_carry(DisasContext *dc, TCGv d)
edgar_igl's avatar
edgar_igl committed
395
{
396 397 398
    if (dc->flagx_known) {
        if (dc->flags_x) {
            TCGv c;
399
            
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
            c = tcg_temp_new();
            t_gen_mov_TN_preg(c, PR_CCS);
            /* C flag is already at bit 0.  */
            tcg_gen_andi_tl(c, c, C_FLAG);
            tcg_gen_add_tl(d, d, c);
            tcg_temp_free(c);
        }
    } else {
        TCGv x, c;

        x = tcg_temp_new();
        c = tcg_temp_new();
        t_gen_mov_TN_preg(x, PR_CCS);
        tcg_gen_mov_tl(c, x);

        /* Propagate carry into d if X is set. Branch free.  */
        tcg_gen_andi_tl(c, c, C_FLAG);
        tcg_gen_andi_tl(x, x, X_FLAG);
        tcg_gen_shri_tl(x, x, 4);

        tcg_gen_and_tl(x, x, c);
        tcg_gen_add_tl(d, d, x);
        tcg_temp_free(x);
        tcg_temp_free(c);
    }
edgar_igl's avatar
edgar_igl committed
425 426
}

427
static inline void t_gen_subx_carry(DisasContext *dc, TCGv d)
edgar_igl's avatar
edgar_igl committed
428
{
429 430 431
    if (dc->flagx_known) {
        if (dc->flags_x) {
            TCGv c;
432
            
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
            c = tcg_temp_new();
            t_gen_mov_TN_preg(c, PR_CCS);
            /* C flag is already at bit 0.  */
            tcg_gen_andi_tl(c, c, C_FLAG);
            tcg_gen_sub_tl(d, d, c);
            tcg_temp_free(c);
        }
    } else {
        TCGv x, c;

        x = tcg_temp_new();
        c = tcg_temp_new();
        t_gen_mov_TN_preg(x, PR_CCS);
        tcg_gen_mov_tl(c, x);

        /* Propagate carry into d if X is set. Branch free.  */
        tcg_gen_andi_tl(c, c, C_FLAG);
        tcg_gen_andi_tl(x, x, X_FLAG);
        tcg_gen_shri_tl(x, x, 4);

        tcg_gen_and_tl(x, x, c);
        tcg_gen_sub_tl(d, d, x);
        tcg_temp_free(x);
        tcg_temp_free(c);
    }
edgar_igl's avatar
edgar_igl committed
458 459 460 461 462 463
}

/* Swap the two bytes within each half word of the s operand.
   T0 = ((T0 << 8) & 0xff00ff00) | ((T0 >> 8) & 0x00ff00ff)  */
static inline void t_gen_swapb(TCGv d, TCGv s)
{
464
    TCGv t, org_s;
edgar_igl's avatar
edgar_igl committed
465

466 467
    t = tcg_temp_new();
    org_s = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
468

469 470 471 472 473 474 475 476 477
    /* d and s may refer to the same object.  */
    tcg_gen_mov_tl(org_s, s);
    tcg_gen_shli_tl(t, org_s, 8);
    tcg_gen_andi_tl(d, t, 0xff00ff00);
    tcg_gen_shri_tl(t, org_s, 8);
    tcg_gen_andi_tl(t, t, 0x00ff00ff);
    tcg_gen_or_tl(d, d, t);
    tcg_temp_free(t);
    tcg_temp_free(org_s);
edgar_igl's avatar
edgar_igl committed
478 479 480 481 482
}

/* Swap the halfwords of the s operand.  */
static inline void t_gen_swapw(TCGv d, TCGv s)
{
483 484 485 486 487 488 489 490
    TCGv t;
    /* d and s refer the same object.  */
    t = tcg_temp_new();
    tcg_gen_mov_tl(t, s);
    tcg_gen_shli_tl(d, t, 16);
    tcg_gen_shri_tl(t, t, 16);
    tcg_gen_or_tl(d, d, t);
    tcg_temp_free(t);
edgar_igl's avatar
edgar_igl committed
491 492 493 494 495 496 497 498 499 500 501 502 503 504
}

/* Reverse the within each byte.
   T0 = (((T0 << 7) & 0x80808080) |
   ((T0 << 5) & 0x40404040) |
   ((T0 << 3) & 0x20202020) |
   ((T0 << 1) & 0x10101010) |
   ((T0 >> 1) & 0x08080808) |
   ((T0 >> 3) & 0x04040404) |
   ((T0 >> 5) & 0x02020202) |
   ((T0 >> 7) & 0x01010101));
 */
static inline void t_gen_swapr(TCGv d, TCGv s)
{
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
    struct {
        int shift; /* LSL when positive, LSR when negative.  */
        uint32_t mask;
    } bitrev[] = {
        {7, 0x80808080},
        {5, 0x40404040},
        {3, 0x20202020},
        {1, 0x10101010},
        {-1, 0x08080808},
        {-3, 0x04040404},
        {-5, 0x02020202},
        {-7, 0x01010101}
    };
    int i;
    TCGv t, org_s;

    /* d and s refer the same object.  */
    t = tcg_temp_new();
    org_s = tcg_temp_new();
    tcg_gen_mov_tl(org_s, s);

    tcg_gen_shli_tl(t, org_s,  bitrev[0].shift);
    tcg_gen_andi_tl(d, t,  bitrev[0].mask);
    for (i = 1; i < ARRAY_SIZE(bitrev); i++) {
        if (bitrev[i].shift >= 0) {
            tcg_gen_shli_tl(t, org_s,  bitrev[i].shift);
        } else {
            tcg_gen_shri_tl(t, org_s,  -bitrev[i].shift);
        }
        tcg_gen_andi_tl(t, t,  bitrev[i].mask);
        tcg_gen_or_tl(d, d, t);
    }
    tcg_temp_free(t);
    tcg_temp_free(org_s);
edgar_igl's avatar
edgar_igl committed
539 540
}

541
static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false)
edgar_igl's avatar
edgar_igl committed
542
{
543
    int l1;
edgar_igl's avatar
edgar_igl committed
544

545
    l1 = gen_new_label();
edgar_igl's avatar
edgar_igl committed
546

547 548 549 550 551
    /* Conditional jmp.  */
    tcg_gen_mov_tl(env_pc, pc_false);
    tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
    tcg_gen_mov_tl(env_pc, pc_true);
    gen_set_label(l1);
edgar_igl's avatar
edgar_igl committed
552 553
}

554 555
static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
{
556 557 558 559 560
    TranslationBlock *tb;
    tb = dc->tb;
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
        tcg_gen_goto_tb(n);
        tcg_gen_movi_tl(env_pc, dest);
561
                tcg_gen_exit_tb((uintptr_t)tb + n);
562 563 564 565
    } else {
        tcg_gen_movi_tl(env_pc, dest);
        tcg_gen_exit_tb(0);
    }
566 567
}

568 569
static inline void cris_clear_x_flag(DisasContext *dc)
{
570 571 572
    if (dc->flagx_known && dc->flags_x) {
        dc->flags_uptodate = 0;
    }
edgar_igl's avatar
edgar_igl committed
573

574 575
    dc->flagx_known = 1;
    dc->flags_x = 0;
576 577
}

578
static void cris_flush_cc_state(DisasContext *dc)
579
{
580 581 582 583 584 585
    if (dc->cc_size_uptodate != dc->cc_size) {
        tcg_gen_movi_tl(cc_size, dc->cc_size);
        dc->cc_size_uptodate = dc->cc_size;
    }
    tcg_gen_movi_tl(cc_op, dc->cc_op);
    tcg_gen_movi_tl(cc_mask, dc->cc_mask);
586 587 588 589
}

static void cris_evaluate_flags(DisasContext *dc)
{
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
    if (dc->flags_uptodate) {
        return;
    }

    cris_flush_cc_state(dc);

    switch (dc->cc_op) {
    case CC_OP_MCP:
        gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS], cpu_env,
                cpu_PR[PR_CCS], cc_src,
                cc_dest, cc_result);
        break;
    case CC_OP_MULS:
        gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS], cpu_env,
                cpu_PR[PR_CCS], cc_result,
                cpu_PR[PR_MOF]);
        break;
    case CC_OP_MULU:
        gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS], cpu_env,
                cpu_PR[PR_CCS], cc_result,
                cpu_PR[PR_MOF]);
        break;
    case CC_OP_MOVE:
    case CC_OP_AND:
    case CC_OP_OR:
    case CC_OP_XOR:
    case CC_OP_ASR:
    case CC_OP_LSR:
    case CC_OP_LSL:
        switch (dc->cc_size) {
        case 4:
            gen_helper_evaluate_flags_move_4(cpu_PR[PR_CCS],
                    cpu_env, cpu_PR[PR_CCS], cc_result);
            break;
        case 2:
            gen_helper_evaluate_flags_move_2(cpu_PR[PR_CCS],
                    cpu_env, cpu_PR[PR_CCS], cc_result);
            break;
        default:
            gen_helper_evaluate_flags(cpu_env);
            break;
        }
        break;
    case CC_OP_FLAGS:
        /* live.  */
        break;
    case CC_OP_SUB:
    case CC_OP_CMP:
        if (dc->cc_size == 4) {
            gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS], cpu_env,
                    cpu_PR[PR_CCS], cc_src, cc_dest, cc_result);
        } else {
            gen_helper_evaluate_flags(cpu_env);
        }

        break;
    default:
        switch (dc->cc_size) {
        case 4:
            gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS], cpu_env,
                    cpu_PR[PR_CCS], cc_src, cc_dest, cc_result);
            break;
        default:
            gen_helper_evaluate_flags(cpu_env);
            break;
655
        }
656 657 658 659 660 661 662 663 664 665 666
        break;
    }

    if (dc->flagx_known) {
        if (dc->flags_x) {
            tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], X_FLAG);
        } else if (dc->cc_op == CC_OP_FLAGS) {
            tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~X_FLAG);
        }
    }
    dc->flags_uptodate = 1;
667 668 669 670
}

static void cris_cc_mask(DisasContext *dc, unsigned int mask)
{
671
    uint32_t ovl;
672

673 674 675 676
    if (!mask) {
        dc->update_cc = 0;
        return;
    }
edgar_igl's avatar
edgar_igl committed
677

678 679 680 681 682 683 684 685 686
    /* Check if we need to evaluate the condition codes due to
       CC overlaying.  */
    ovl = (dc->cc_mask ^ mask) & ~mask;
    if (ovl) {
        /* TODO: optimize this case. It trigs all the time.  */
        cris_evaluate_flags(dc);
    }
    dc->cc_mask = mask;
    dc->update_cc = 1;
687 688
}

edgar_igl's avatar
edgar_igl committed
689
static void cris_update_cc_op(DisasContext *dc, int op, int size)
690
{
691 692 693
    dc->cc_op = op;
    dc->cc_size = size;
    dc->flags_uptodate = 0;
694 695
}

696 697
static inline void cris_update_cc_x(DisasContext *dc)
{
698 699 700 701 702 703 704 705 706 707 708
    /* Save the x flag state at the time of the cc snapshot.  */
    if (dc->flagx_known) {
        if (dc->cc_x_uptodate == (2 | dc->flags_x)) {
            return;
        }
        tcg_gen_movi_tl(cc_x, dc->flags_x);
        dc->cc_x_uptodate = 2 | dc->flags_x;
    } else {
        tcg_gen_andi_tl(cc_x, cpu_PR[PR_CCS], X_FLAG);
        dc->cc_x_uptodate = 1;
    }
709 710 711 712
}

/* Update cc prior to executing ALU op. Needs source operands untouched.  */
static void cris_pre_alu_update_cc(DisasContext *dc, int op, 
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
                   TCGv dst, TCGv src, int size)
{
    if (dc->update_cc) {
        cris_update_cc_op(dc, op, size);
        tcg_gen_mov_tl(cc_src, src);

        if (op != CC_OP_MOVE
            && op != CC_OP_AND
            && op != CC_OP_OR
            && op != CC_OP_XOR
            && op != CC_OP_ASR
            && op != CC_OP_LSR
            && op != CC_OP_LSL) {
            tcg_gen_mov_tl(cc_dest, dst);
        }
728

729 730
        cris_update_cc_x(dc);
    }
731
}
edgar_igl's avatar
edgar_igl committed
732

733 734 735
/* Update cc after executing ALU op. needs the result.  */
static inline void cris_update_result(DisasContext *dc, TCGv res)
{
736 737 738
    if (dc->update_cc) {
        tcg_gen_mov_tl(cc_result, res);
    }
739
}
740

741 742
/* Returns one if the write back stage should execute.  */
static void cris_alu_op_exec(DisasContext *dc, int op, 
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
                   TCGv dst, TCGv a, TCGv b, int size)
{
    /* Emit the ALU insns.  */
    switch (op) {
    case CC_OP_ADD:
        tcg_gen_add_tl(dst, a, b);
        /* Extended arithmetics.  */
        t_gen_addx_carry(dc, dst);
        break;
    case CC_OP_ADDC:
        tcg_gen_add_tl(dst, a, b);
        t_gen_add_flag(dst, 0); /* C_FLAG.  */
        break;
    case CC_OP_MCP:
        tcg_gen_add_tl(dst, a, b);
        t_gen_add_flag(dst, 8); /* R_FLAG.  */
        break;
    case CC_OP_SUB:
        tcg_gen_sub_tl(dst, a, b);
        /* Extended arithmetics.  */
        t_gen_subx_carry(dc, dst);
        break;
    case CC_OP_MOVE:
        tcg_gen_mov_tl(dst, b);
        break;
    case CC_OP_OR:
        tcg_gen_or_tl(dst, a, b);
        break;
    case CC_OP_AND:
        tcg_gen_and_tl(dst, a, b);
        break;
    case CC_OP_XOR:
        tcg_gen_xor_tl(dst, a, b);
        break;
    case CC_OP_LSL:
        t_gen_lsl(dst, a, b);
        break;
    case CC_OP_LSR:
        t_gen_lsr(dst, a, b);
        break;
    case CC_OP_ASR:
        t_gen_asr(dst, a, b);
        break;
    case CC_OP_NEG:
        tcg_gen_neg_tl(dst, b);
        /* Extended arithmetics.  */
        t_gen_subx_carry(dc, dst);
        break;
    case CC_OP_LZ:
        gen_helper_lz(dst, b);
        break;
    case CC_OP_MULS:
795
        tcg_gen_muls2_tl(dst, cpu_PR[PR_MOF], a, b);
796 797
        break;
    case CC_OP_MULU:
798
        tcg_gen_mulu2_tl(dst, cpu_PR[PR_MOF], a, b);
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
        break;
    case CC_OP_DSTEP:
        t_gen_cris_dstep(dst, a, b);
        break;
    case CC_OP_MSTEP:
        t_gen_cris_mstep(dst, a, b, cpu_PR[PR_CCS]);
        break;
    case CC_OP_BOUND:
    {
        int l1;
        l1 = gen_new_label();
        tcg_gen_mov_tl(dst, a);
        tcg_gen_brcond_tl(TCG_COND_LEU, a, b, l1);
        tcg_gen_mov_tl(dst, b);
        gen_set_label(l1);
    }
        break;
    case CC_OP_CMP:
        tcg_gen_sub_tl(dst, a, b);
        /* Extended arithmetics.  */
        t_gen_subx_carry(dc, dst);
        break;
    default:
        qemu_log("illegal ALU op.\n");
        BUG();
        break;
    }

    if (size == 1) {
        tcg_gen_andi_tl(dst, dst, 0xff);
    } else if (size == 2) {
        tcg_gen_andi_tl(dst, dst, 0xffff);
    }
832 833 834
}

static void cris_alu(DisasContext *dc, int op,
835
                   TCGv d, TCGv op_a, TCGv op_b, int size)
836
{
837 838
    TCGv tmp;
    int writeback;
839

840
    writeback = 1;
edgar_igl's avatar
edgar_igl committed
841

842 843 844 845 846 847 848 849 850
    if (op == CC_OP_CMP) {
        tmp = tcg_temp_new();
        writeback = 0;
    } else if (size == 4) {
        tmp = d;
        writeback = 0;
    } else {
        tmp = tcg_temp_new();
    }
edgar_igl's avatar
edgar_igl committed
851

852

853 854 855
    cris_pre_alu_update_cc(dc, op, op_a, op_b, size);
    cris_alu_op_exec(dc, op, tmp, op_a, op_b, size);
    cris_update_result(dc, tmp);
856

857 858 859 860 861 862 863 864 865 866 867 868
    /* Writeback.  */
    if (writeback) {
        if (size == 1) {
            tcg_gen_andi_tl(d, d, ~0xff);
        } else {
            tcg_gen_andi_tl(d, d, ~0xffff);
        }
        tcg_gen_or_tl(d, d, tmp);
    }
    if (!TCGV_EQUAL(tmp, d)) {
        tcg_temp_free(tmp);
    }
869 870 871 872
}

static int arith_cc(DisasContext *dc)
{
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
    if (dc->update_cc) {
        switch (dc->cc_op) {
        case CC_OP_ADDC: return 1;
        case CC_OP_ADD: return 1;
        case CC_OP_SUB: return 1;
        case CC_OP_DSTEP: return 1;
        case CC_OP_LSL: return 1;
        case CC_OP_LSR: return 1;
        case CC_OP_ASR: return 1;
        case CC_OP_CMP: return 1;
        case CC_OP_NEG: return 1;
        case CC_OP_OR: return 1;
        case CC_OP_AND: return 1;
        case CC_OP_XOR: return 1;
        case CC_OP_MULU: return 1;
        case CC_OP_MULS: return 1;
        default:
            return 0;
        }
    }
    return 0;
894 895
}

896
static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
897
{
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
    int arith_opt, move_opt;

    /* TODO: optimize more condition codes.  */

    /*
     * If the flags are live, we've gotta look into the bits of CCS.
     * Otherwise, if we just did an arithmetic operation we try to
     * evaluate the condition code faster.
     *
     * When this function is done, T0 should be non-zero if the condition
     * code is true.
     */
    arith_opt = arith_cc(dc) && !dc->flags_uptodate;
    move_opt = (dc->cc_op == CC_OP_MOVE);
    switch (cond) {
    case CC_EQ:
        if ((arith_opt || move_opt)
                && dc->cc_x_uptodate != (2 | X_FLAG)) {
            tcg_gen_setcond_tl(TCG_COND_EQ, cc,
                    cc_result, tcg_const_tl(0));
        } else {
            cris_evaluate_flags(dc);
            tcg_gen_andi_tl(cc,
                    cpu_PR[PR_CCS], Z_FLAG);
        }
        break;
    case CC_NE:
        if ((arith_opt || move_opt)
                && dc->cc_x_uptodate != (2 | X_FLAG)) {
            tcg_gen_mov_tl(cc, cc_result);
        } else {
            cris_evaluate_flags(dc);
            tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
                    Z_FLAG);
            tcg_gen_andi_tl(cc, cc, Z_FLAG);
        }
        break;
    case CC_CS:
        cris_evaluate_flags(dc);
        tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], C_FLAG);
        break;
    case CC_CC:
        cris_evaluate_flags(dc);
        tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], C_FLAG);
        tcg_gen_andi_tl(cc, cc, C_FLAG);
        break;
    case CC_VS:
        cris_evaluate_flags(dc);
        tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], V_FLAG);
        break;
    case CC_VC:
        cris_evaluate_flags(dc);
        tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
                V_FLAG);
        tcg_gen_andi_tl(cc, cc, V_FLAG);
        break;
    case CC_PL:
        if (arith_opt || move_opt) {
            int bits = 31;

            if (dc->cc_size == 1) {
                bits = 7;
            } else if (dc->cc_size == 2) {
                bits = 15;
            }

            tcg_gen_shri_tl(cc, cc_result, bits);
            tcg_gen_xori_tl(cc, cc, 1);
        } else {
            cris_evaluate_flags(dc);
            tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
                    N_FLAG);
            tcg_gen_andi_tl(cc, cc, N_FLAG);
        }
        break;
    case CC_MI:
        if (arith_opt || move_opt) {
            int bits = 31;

            if (dc->cc_size == 1) {
                bits = 7;
            } else if (dc->cc_size == 2) {
                bits = 15;
            }

            tcg_gen_shri_tl(cc, cc_result, bits);
            tcg_gen_andi_tl(cc, cc, 1);
        } else {
            cris_evaluate_flags(dc);
            tcg_gen_andi_tl(cc, cpu_PR[PR_CCS],
                    N_FLAG);
        }
        break;
    case CC_LS:
        cris_evaluate_flags(dc);
        tcg_gen_andi_tl(cc, cpu_PR[PR_CCS],
                C_FLAG | Z_FLAG);
        break;
    case CC_HI:
        cris_evaluate_flags(dc);
        {
            TCGv tmp;

            tmp = tcg_temp_new();
            tcg_gen_xori_tl(tmp, cpu_PR[PR_CCS],
                    C_FLAG | Z_FLAG);
            /* Overlay the C flag on top of the Z.  */
            tcg_gen_shli_tl(cc, tmp, 2);
            tcg_gen_and_tl(cc, tmp, cc);
            tcg_gen_andi_tl(cc, cc, Z_FLAG);

            tcg_temp_free(tmp);
        }
        break;
    case CC_GE:
        cris_evaluate_flags(dc);
        /* Overlay the V flag on top of the N.  */
        tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2);
        tcg_gen_xor_tl(cc,
                cpu_PR[PR_CCS], cc);
        tcg_gen_andi_tl(cc, cc, N_FLAG);
        tcg_gen_xori_tl(cc, cc, N_FLAG);
        break;
    case CC_LT:
        cris_evaluate_flags(dc);
        /* Overlay the V flag on top of the N.  */
        tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2);
        tcg_gen_xor_tl(cc,
                cpu_PR[PR_CCS], cc);
        tcg_gen_andi_tl(cc, cc, N_FLAG);
        break;
    case CC_GT:
        cris_evaluate_flags(dc);
        {
            TCGv n, z;

            n = tcg_temp_new();
            z = tcg_temp_new();

            /* To avoid a shift we overlay everything on
                   the V flag.  */
            tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2);
            tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1);
            /* invert Z.  */
            tcg_gen_xori_tl(z, z, 2);

            tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]);
            tcg_gen_xori_tl(n, n, 2);
            tcg_gen_and_tl(cc, z, n);
            tcg_gen_andi_tl(cc, cc, 2);

            tcg_temp_free(n);
            tcg_temp_free(z);
        }
        break;
    case CC_LE:
        cris_evaluate_flags(dc);
        {
            TCGv n, z;

            n = tcg_temp_new();
            z = tcg_temp_new();

            /* To avoid a shift we overlay everything on
                   the V flag.  */
            tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2);
            tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1);

            tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]);
            tcg_gen_or_tl(cc, z, n);
            tcg_gen_andi_tl(cc, cc, 2);

            tcg_temp_free(n);
            tcg_temp_free(z);
        }
        break;
    case CC_P:
        cris_evaluate_flags(dc);
        tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], P_FLAG);
        break;
    case CC_A:
        tcg_gen_movi_tl(cc, 1);
        break;
    default:
        BUG();
        break;
    };
1085 1086
}

edgar_igl's avatar
edgar_igl committed
1087 1088
static void cris_store_direct_jmp(DisasContext *dc)
{
1089 1090 1091 1092 1093 1094 1095 1096
    /* Store the direct jmp state into the cpu-state.  */
    if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
        if (dc->jmp == JMP_DIRECT) {
            tcg_gen_movi_tl(env_btaken, 1);
        }
        tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
        dc->jmp = JMP_INDIRECT;
    }
edgar_igl's avatar
edgar_igl committed
1097 1098 1099
}

static void cris_prepare_cc_branch (DisasContext *dc, 
1100
                    int offset, int cond)
1101
{
1102 1103 1104 1105 1106
    /* This helps us re-schedule the micro-code to insns in delay-slots
       before the actual jump.  */
    dc->delayed_branch = 2;
    dc->jmp = JMP_DIRECT_CC;
    dc->jmp_pc = dc->pc + offset;
edgar_igl's avatar
edgar_igl committed
1107

1108 1109
    gen_tst_cc(dc, env_btaken, cond);
    tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
1110 1111
}

edgar_igl's avatar
edgar_igl committed
1112

edgar_igl's avatar
edgar_igl committed
1113 1114 1115
/* jumps, when the dest is in a live reg for example. Direct should be set
   when the dest addr is constant to allow tb chaining.  */
static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type)
1116
{
1117 1118 1119 1120 1121 1122 1123
    /* This helps us re-schedule the micro-code to insns in delay-slots
       before the actual jump.  */
    dc->delayed_branch = 2;
    dc->jmp = type;
    if (type == JMP_INDIRECT) {
        tcg_gen_movi_tl(env_btaken, 1);
    }
1124 1125
}

pbrook's avatar
pbrook committed
1126 1127
static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr)
{
1128
    int mem_index = cpu_mmu_index(dc->env);
pbrook's avatar
pbrook committed
1129

1130 1131 1132 1133 1134
    /* If we get a fault on a delayslot we must keep the jmp state in
       the cpu-state to be able to re-execute the jmp.  */
    if (dc->delayed_branch == 1) {
        cris_store_direct_jmp(dc);
    }
pbrook's avatar
pbrook committed
1135

1136
    tcg_gen_qemu_ld_i64(dst, addr, mem_index, MO_TEQ);
pbrook's avatar
pbrook committed
1137 1138
}

edgar_igl's avatar
edgar_igl committed
1139
static void gen_load(DisasContext *dc, TCGv dst, TCGv addr, 
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
             unsigned int size, int sign)
{
    int mem_index = cpu_mmu_index(dc->env);

    /* If we get a fault on a delayslot we must keep the jmp state in
       the cpu-state to be able to re-execute the jmp.  */
    if (dc->delayed_branch == 1) {
        cris_store_direct_jmp(dc);
    }

1150 1151
    tcg_gen_qemu_ld_tl(dst, addr, mem_index,
                       MO_TE + ctz32(size) + (sign ? MO_SIGN : 0));
1152 1153
}

edgar_igl's avatar
edgar_igl committed
1154
static void gen_store (DisasContext *dc, TCGv addr, TCGv val,
1155
               unsigned int size)
1156
{
1157
    int mem_index = cpu_mmu_index(dc->env);
edgar_igl's avatar
edgar_igl committed
1158

1159 1160 1161 1162 1163
    /* If we get a fault on a delayslot we must keep the jmp state in
       the cpu-state to be able to re-execute the jmp.  */
    if (dc->delayed_branch == 1) {
        cris_store_direct_jmp(dc);
    }
edgar_igl's avatar
edgar_igl committed
1164 1165


1166 1167 1168 1169 1170 1171 1172 1173
    /* Conditional writes. We only support the kind were X and P are known
       at translation time.  */
    if (dc->flagx_known && dc->flags_x && (dc->tb_flags & P_FLAG)) {
        dc->postinc = 0;
        cris_evaluate_flags(dc);
        tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], C_FLAG);
        return;
    }
edgar_igl's avatar
edgar_igl committed
1174

1175
    tcg_gen_qemu_st_tl(val, addr, mem_index, MO_TE + ctz32(size));
edgar_igl's avatar
edgar_igl committed
1176

1177 1178 1179 1180
    if (dc->flagx_known && dc->flags_x) {
        cris_evaluate_flags(dc);
        tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~C_FLAG);
    }
1181 1182
}

1183
static inline void t_gen_sext(TCGv d, TCGv s, int size)
1184
{
1185 1186 1187 1188 1189 1190 1191
    if (size == 1) {
        tcg_gen_ext8s_i32(d, s);
    } else if (size == 2) {
        tcg_gen_ext16s_i32(d, s);
    } else if (!TCGV_EQUAL(d, s)) {
        tcg_gen_mov_tl(d, s);
    }
1192 1193
}

1194
static inline void t_gen_zext(TCGv d, TCGv s, int size)
1195
{
1196 1197 1198 1199 1200 1201 1202
    if (size == 1) {
        tcg_gen_ext8u_i32(d, s);
    } else if (size == 2) {
        tcg_gen_ext16u_i32(d, s);
    } else if (!TCGV_EQUAL(d, s)) {
        tcg_gen_mov_tl(d, s);
    }
1203 1204 1205 1206 1207
}

#if DISAS_CRIS
static char memsize_char(int size)
{
1208 1209 1210 1211 1212 1213 1214 1215
    switch (size) {
    case 1: return 'b';  break;
    case 2: return 'w';  break;
    case 4: return 'd';  break;
    default:
        return 'x';
        break;
    }
1216 1217 1218
}
#endif

1219
static inline unsigned int memsize_z(DisasContext *dc)
1220
{
1221
    return dc->zsize + 1;
1222 1223
}

1224
static inline unsigned int memsize_zz(DisasContext *dc)
1225
{
1226 1227 1228 1229 1230 1231
    switch (dc->zzsize) {
    case 0: return 1;
    case 1: return 2;
    default:
        return 4;
    }
1232 1233
}

1234
static inline void do_postinc (DisasContext *dc, int size)
1235
{
1236 1237 1238
    if (dc->postinc) {
        tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], size);
    }
1239 1240
}

1241
static inline void dec_prep_move_r(DisasContext *dc, int rs, int rd,
1242
                   int size, int s_ext, TCGv dst)
1243
{
1244 1245 1246 1247 1248
    if (s_ext) {
        t_gen_sext(dst, cpu_R[rs], size);
    } else {
        t_gen_zext(dst, cpu_R[rs], size);
    }
1249 1250 1251 1252 1253 1254
}

/* Prepare T0 and T1 for a register alu operation.
   s_ext decides if the operand1 should be sign-extended or zero-extended when
   needed.  */
static void dec_prep_alu_r(DisasContext *dc, int rs, int rd,
1255
              int size, int s_ext, TCGv dst, TCGv src)
1256
{
1257
    dec_prep_move_r(dc, rs, rd, size, s_ext, src);
1258

1259 1260 1261 1262 1263
    if (s_ext) {
        t_gen_sext(dst, cpu_R[rd], size);
    } else {
        t_gen_zext(dst, cpu_R[rd], size);
    }
1264 1265
}

1266 1267
static int dec_prep_move_m(CPUCRISState *env, DisasContext *dc,
                           int s_ext, int memsize, TCGv dst)
1268
{
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
    unsigned int rs;
    uint32_t imm;
    int is_imm;
    int insn_len = 2;

    rs = dc->op1;
    is_imm = rs == 15 && dc->postinc;

    /* Load [$rs] onto T1.  */
    if (is_imm) {
        insn_len = 2 + memsize;
        if (memsize == 1) {
            insn_len++;
        }

        imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext);
        tcg_gen_movi_tl(dst, imm);
        dc->postinc = 0;
    } else {
        cris_flush_cc_state(dc);
        gen_load(dc, dst, cpu_R[rs], memsize, 0);
        if (s_ext) {
            t_gen_sext(dst, dst, memsize);
        } else {
            t_gen_zext(dst, dst, memsize);
        }
    }
    return insn_len;
1297 1298 1299 1300 1301
}

/* Prepare T0 and T1 for a memory + alu operation.
   s_ext decides if the operand1 should be sign-extended or zero-extended when
   needed.  */
1302 1303
static int dec_prep_alu_m(CPUCRISState *env, DisasContext *dc,
                          int s_ext, int memsize, TCGv dst, TCGv src)
1304
{
1305
    int insn_len;
1306

1307 1308 1309
    insn_len = dec_prep_move_m(env, dc, s_ext, memsize, src);
    tcg_gen_mov_tl(dst, cpu_R[dc->op2]);
    return insn_len;
1310 1311 1312 1313 1314
}

#if DISAS_CRIS
static const char *cc_name(int cc)
{
1315 1316 1317 1318 1319 1320
    static const char *cc_names[16] = {
        "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi",
        "ls", "hi", "ge", "lt", "gt", "le", "a", "p"
    };
    assert(cc < 16);
    return cc_names[cc];
1321 1322 1323
}
#endif

edgar_igl's avatar
edgar_igl committed
1324 1325
/* Start of insn decoders.  */

1326
static int dec_bccq(CPUCRISState *env, DisasContext *dc)
1327
{
1328 1329 1330
    int32_t offset;
    int sign;
    uint32_t cond = dc->op2;
1331

1332 1333
    offset = EXTRACT_FIELD(dc->ir, 1, 7);
    sign = EXTRACT_FIELD(dc->ir, 0, 0);
1334

1335 1336 1337
    offset *= 2;
    offset |= sign << 8;
    offset = sign_extend(offset, 8);
1338

1339
    LOG_DIS("b%s %x\n", cc_name(cond), dc->pc + offset);
edgar_igl's avatar
edgar_igl committed
1340

1341 1342 1343 1344
    /* op2 holds the condition-code.  */
    cris_cc_mask(dc, 0);
    cris_prepare_cc_branch(dc, offset, cond);
    return 2;
1345
}
1346
static int dec_addoq(CPUCRISState *env, DisasContext *dc)
1347
{
1348
    int32_t imm;
1349

1350 1351
    dc->op1 = EXTRACT_FIELD(dc->ir, 0, 7);
    imm = sign_extend(dc->op1, 7);
1352

1353 1354 1355 1356
    LOG_DIS("addoq %d, $r%u\n", imm, dc->op2);
    cris_cc_mask(dc, 0);
    /* Fetch register operand,  */
    tcg_gen_addi_tl(cpu_R[R_ACR], cpu_R[dc->op2], imm);
edgar_igl's avatar
edgar_igl committed
1357

1358
    return 2;
1359
}
1360
static int dec_addq(CPUCRISState *env, DisasContext *dc)
1361
{
1362
    LOG_DIS("addq %u, $r%u\n", dc->op1, dc->op2);
1363

1364
    dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
1365

1366
    cris_cc_mask(dc, CC_MASK_NZVC);
1367

1368 1369 1370
    cris_alu(dc, CC_OP_ADD,
            cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4);
    return 2;
1371
}
1372
static int dec_moveq(CPUCRISState *env, DisasContext *dc)
1373
{
1374
    uint32_t imm;
1375

1376 1377 1378
    dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
    imm = sign_extend(dc->op1, 5);
    LOG_DIS("moveq %d, $r%u\n", imm, dc->op2);
1379

1380 1381
    tcg_gen_movi_tl(cpu_R[dc->op2], imm);
    return 2;
1382
}
1383
static int dec_subq(CPUCRISState *env, DisasContext *dc)
1384
{
1385
    dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
1386

1387
    LOG_DIS("subq %u, $r%u\n", dc->op1, dc->op2);
1388

1389 1390 1391 1392
    cris_cc_mask(dc, CC_MASK_NZVC);
    cris_alu(dc, CC_OP_SUB,
            cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4);
    return 2;
1393
}
1394
static int dec_cmpq(CPUCRISState *env, DisasContext *dc)
1395
{
1396 1397 1398
    uint32_t imm;
    dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
    imm = sign_extend(dc->op1, 5);
1399

1400 1401
    LOG_DIS("cmpq %d, $r%d\n", imm, dc->op2);
    cris_cc_mask(dc, CC_MASK_NZVC);
1402

1403 1404 1405
    cris_alu(dc, CC_OP_CMP,
            cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4);
    return 2;
1406
}
1407
static int dec_andq(CPUCRISState *env, DisasContext *dc)
1408
{
1409 1410 1411
    uint32_t imm;
    dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
    imm = sign_extend(dc->op1, 5);
1412

1413 1414
    LOG_DIS("andq %d, $r%d\n", imm, dc->op2);
    cris_cc_mask(dc, CC_MASK_NZ);
1415

1416 1417 1418
    cris_alu(dc, CC_OP_AND,
            cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4);
    return 2;
1419
}
1420
static int dec_orq(CPUCRISState *env, DisasContext *dc)
1421
{