translate.c 83.7 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 18 19 20 21
 *  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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

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

27 28 29 30 31 32 33 34 35 36
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <assert.h>

#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
bellard's avatar
bellard committed
37
#include "tcg-op.h"
38
#include "helper.h"
39
#include "crisv32-decode.h"
40
#include "qemu-common.h"
41

pbrook's avatar
pbrook committed
42 43 44
#define GEN_HELPER 1
#include "helper.h"

45 46
#define DISAS_CRIS 0
#if DISAS_CRIS
47
#define DIS(x) if (loglevel & CPU_LOG_TB_IN_ASM) x
48 49 50 51
#else
#define DIS(x)
#endif

edgar_igl's avatar
edgar_igl committed
52
#define D(x)
53 54 55
#define BUG() (gen_BUG(dc, __FILE__, __LINE__))
#define BUG_ON(x) ({if (x) BUG();})

56 57
#define DISAS_SWI 5

58 59 60 61 62 63 64 65 66
/* 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
67
static TCGv_ptr cpu_env;
edgar_igl's avatar
edgar_igl committed
68 69 70 71 72 73 74 75 76 77 78 79 80
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
81

pbrook's avatar
pbrook committed
82 83
#include "gen-icount.h"

84 85 86
/* This is the state at translation time.  */
typedef struct DisasContext {
	CPUState *env;
edgar_igl's avatar
edgar_igl committed
87
	target_ulong pc, ppc;
88 89 90 91 92 93 94 95 96 97 98 99 100 101

	/* Decoder.  */
	uint32_t ir;
	uint32_t opcode;
	unsigned int op1;
	unsigned int op2;
	unsigned int zsize, zzsize;
	unsigned int mode;
	unsigned int postinc;

	int update_cc;
	int cc_op;
	int cc_size;
	uint32_t cc_mask;
102 103 104 105 106 107 108

	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.  */
109 110
	int flags_x;

111
	int clear_x; /* Clear x after this insn?  */
edgar_igl's avatar
edgar_igl committed
112 113
	int cpustate_changed;
	unsigned int tb_flags; /* tb dependent flags.  */
114 115
	int is_jmp;

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

122 123 124 125 126 127
	int delayed_branch;

	struct TranslationBlock *tb;
	int singlestep_enabled;
} DisasContext;

128
static void gen_BUG(DisasContext *dc, const char *file, int line)
129 130 131
{
	printf ("BUG: pc=%x %s %d\n", dc->pc, file, line);
	fprintf (logfile, "BUG: pc=%x %s %d\n", dc->pc, file, line);
132
	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 141
{
	"$r0", "$r1", "$r2", "$r3",
	"$r4", "$r5", "$r6", "$r7",
	"$r8", "$r9", "$r10", "$r11",
	"$r12", "$r13", "$sp", "$acr",
};
edgar_igl's avatar
edgar_igl committed
142
static const char *pregnames[] =
edgar_igl's avatar
edgar_igl committed
143 144 145 146 147 148 149
{
	"$bz", "$vr", "$pid", "$srs",
	"$wz", "$exs", "$eda", "$mof",
	"$dz", "$ebp", "$erp", "$srp",
	"$nrp", "$ccs", "$usp", "$spc",
};

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 160 161 162
	1, /* bz.  */
	1, /* vr.  */
	4, /* pid.  */
	1, /* srs.  */
	2, /* wz.  */
	4, 4, 4,
	4, 4, 4, 4,
	4, 4, 4, 4,
};

#define t_gen_mov_TN_env(tn, member) \
edgar_igl's avatar
edgar_igl committed
163
 _t_gen_mov_TN_env((tn), offsetof(CPUState, member))
164
#define t_gen_mov_env_TN(member, tn) \
edgar_igl's avatar
edgar_igl committed
165
 _t_gen_mov_env_TN(offsetof(CPUState, member), (tn))
166

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

static inline void _t_gen_mov_TN_env(TCGv tn, int offset)
{
edgar_igl's avatar
edgar_igl committed
182 183
	if (offset > sizeof (CPUState))
		fprintf(stderr, "wrong load from env from off=%d\n", offset);
184 185 186 187
	tcg_gen_ld_tl(tn, cpu_env, offset);
}
static inline void _t_gen_mov_env_TN(int offset, TCGv tn)
{
edgar_igl's avatar
edgar_igl committed
188 189
	if (offset > sizeof (CPUState))
		fprintf(stderr, "wrong store to env at off=%d\n", offset);
190 191 192 193 194
	tcg_gen_st_tl(tn, cpu_env, offset);
}

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

edgar_igl's avatar
edgar_igl committed
227
static inline void t_gen_raise_exception(uint32_t index)
228
{
pbrook's avatar
pbrook committed
229 230 231
        TCGv_i32 tmp = tcg_const_i32(index);
	gen_helper_raise_exception(tmp);
        tcg_temp_free_i32(tmp);
232 233 234 235
}

static void t_gen_lsl(TCGv d, TCGv a, TCGv b)
{
236
	TCGv t0, t_31;
237

pbrook's avatar
pbrook committed
238
	t0 = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
239
	t_31 = tcg_const_tl(31);
240
	tcg_gen_shl_tl(d, a, b);
241 242 243 244 245 246 247

	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);
248 249 250 251
}

static void t_gen_lsr(TCGv d, TCGv a, TCGv b)
{
252
	TCGv t0, t_31;
253

pbrook's avatar
pbrook committed
254 255
	t0 = tcg_temp_new();
	t_31 = tcg_temp_new();
256
	tcg_gen_shr_tl(d, a, b);
257 258 259 260 261 262 263 264

	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);
265 266 267 268
}

static void t_gen_asr(TCGv d, TCGv a, TCGv b)
{
269
	TCGv t0, t_31;
270

pbrook's avatar
pbrook committed
271 272
	t0 = tcg_temp_new();
	t_31 = tcg_temp_new();
273
	tcg_gen_sar_tl(d, a, b);
274 275 276 277 278 279 280

	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);
281 282
}

edgar_igl's avatar
edgar_igl committed
283 284 285
/* 64-bit signed mul, lower result in d and upper in d2.  */
static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b)
{
pbrook's avatar
pbrook committed
286
	TCGv_i64 t0, t1;
edgar_igl's avatar
edgar_igl committed
287

pbrook's avatar
pbrook committed
288 289
	t0 = tcg_temp_new_i64();
	t1 = tcg_temp_new_i64();
edgar_igl's avatar
edgar_igl committed
290

pbrook's avatar
pbrook committed
291 292
	tcg_gen_ext_i32_i64(t0, a);
	tcg_gen_ext_i32_i64(t1, b);
edgar_igl's avatar
edgar_igl committed
293 294 295 296 297
	tcg_gen_mul_i64(t0, t0, t1);

	tcg_gen_trunc_i64_i32(d, t0);
	tcg_gen_shri_i64(t0, t0, 32);
	tcg_gen_trunc_i64_i32(d2, t0);
edgar_igl's avatar
edgar_igl committed
298

pbrook's avatar
pbrook committed
299 300
	tcg_temp_free_i64(t0);
	tcg_temp_free_i64(t1);
edgar_igl's avatar
edgar_igl committed
301 302 303 304 305
}

/* 64-bit unsigned muls, lower result in d and upper in d2.  */
static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b)
{
pbrook's avatar
pbrook committed
306
	TCGv_i64 t0, t1;
edgar_igl's avatar
edgar_igl committed
307

pbrook's avatar
pbrook committed
308 309
	t0 = tcg_temp_new_i64();
	t1 = tcg_temp_new_i64();
edgar_igl's avatar
edgar_igl committed
310 311 312 313 314 315 316 317

	tcg_gen_extu_i32_i64(t0, a);
	tcg_gen_extu_i32_i64(t1, b);
	tcg_gen_mul_i64(t0, t0, t1);

	tcg_gen_trunc_i64_i32(d, t0);
	tcg_gen_shri_i64(t0, t0, 32);
	tcg_gen_trunc_i64_i32(d2, t0);
edgar_igl's avatar
edgar_igl committed
318

pbrook's avatar
pbrook committed
319 320
	tcg_temp_free_i64(t0);
	tcg_temp_free_i64(t1);
edgar_igl's avatar
edgar_igl committed
321 322
}

323 324 325
/* 32bit branch-free binary search for counting leading zeros.  */
static void t_gen_lz_i32(TCGv d, TCGv x)
{
pbrook's avatar
pbrook committed
326
	TCGv_i32 y, m, n;
327

pbrook's avatar
pbrook committed
328 329 330
	y = tcg_temp_new_i32();
	m = tcg_temp_new_i32();
	n = tcg_temp_new_i32();
331 332 333

	/* y = -(x >> 16)  */
	tcg_gen_shri_i32(y, x, 16);
pbrook's avatar
pbrook committed
334
	tcg_gen_neg_i32(y, y);
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378

	/* m = (y >> 16) & 16  */
	tcg_gen_sari_i32(m, y, 16);
	tcg_gen_andi_i32(m, m, 16);

	/* n = 16 - m  */
	tcg_gen_sub_i32(n, tcg_const_i32(16), m);
	/* x = x >> m  */
	tcg_gen_shr_i32(x, x, m);

	/* y = x - 0x100  */
	tcg_gen_subi_i32(y, x, 0x100);
	/* m = (y >> 16) & 8  */
	tcg_gen_sari_i32(m, y, 16);
	tcg_gen_andi_i32(m, m, 8);
	/* n = n + m  */
	tcg_gen_add_i32(n, n, m);
	/* x = x << m  */
	tcg_gen_shl_i32(x, x, m);

	/* y = x - 0x1000  */
	tcg_gen_subi_i32(y, x, 0x1000);
	/* m = (y >> 16) & 4  */
	tcg_gen_sari_i32(m, y, 16);
	tcg_gen_andi_i32(m, m, 4);
	/* n = n + m  */
	tcg_gen_add_i32(n, n, m);
	/* x = x << m  */
	tcg_gen_shl_i32(x, x, m);

	/* y = x - 0x4000  */
	tcg_gen_subi_i32(y, x, 0x4000);
	/* m = (y >> 16) & 2  */
	tcg_gen_sari_i32(m, y, 16);
	tcg_gen_andi_i32(m, m, 2);
	/* n = n + m  */
	tcg_gen_add_i32(n, n, m);
	/* x = x << m  */
	tcg_gen_shl_i32(x, x, m);

	/* y = x >> 14  */
	tcg_gen_shri_i32(y, x, 14);
	/* m = y & ~(y >> 1)  */
	tcg_gen_sari_i32(m, y, 1);
edgar_igl's avatar
edgar_igl committed
379
	tcg_gen_not_i32(m, m);
380 381 382 383 384 385
	tcg_gen_and_i32(m, m, y);

	/* d = n + 2 - m  */
	tcg_gen_addi_i32(d, n, 2);
	tcg_gen_sub_i32(d, d, m);

386 387 388
	tcg_temp_free(y);
	tcg_temp_free(m);
	tcg_temp_free(n);
389 390
}

391
static void t_gen_btst(TCGv d, TCGv a, TCGv b)
edgar_igl's avatar
edgar_igl committed
392 393 394
{
        TCGv sbit;
        TCGv bset;
395
        TCGv t0;
edgar_igl's avatar
edgar_igl committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
	int l1;

        /* des ref:
           The N flag is set according to the selected bit in the dest reg.
           The Z flag is set if the selected bit and all bits to the right are
           zero.
           The X flag is cleared.
           Other flags are left untouched.
           The destination reg is not affected.

        unsigned int fz, sbit, bset, mask, masked_t0;

        sbit = T1 & 31;
        bset = !!(T0 & (1 << sbit));
        mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1;
        masked_t0 = T0 & mask;
        fz = !(masked_t0 | bset);

        // Clear the X, N and Z flags.
        T0 = env->pregs[PR_CCS] & ~(X_FLAG | N_FLAG | Z_FLAG);
        // Set the N and Z flags accordingly.
        T0 |= (bset << 3) | (fz << 2);
        */

	l1 = gen_new_label();
pbrook's avatar
pbrook committed
421 422 423
        sbit = tcg_temp_new();
        bset = tcg_temp_new();
        t0 = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
424 425

        /* Compute bset and sbit.  */
426 427 428
        tcg_gen_andi_tl(sbit, b, 31);
        tcg_gen_shl_tl(t0, tcg_const_tl(1), sbit);
        tcg_gen_and_tl(bset, a, t0);
edgar_igl's avatar
edgar_igl committed
429 430 431 432 433 434
        tcg_gen_shr_tl(bset, bset, sbit);
	/* Displace to N_FLAG.  */
        tcg_gen_shli_tl(bset, bset, 3);

        tcg_gen_shl_tl(sbit, tcg_const_tl(2), sbit);
        tcg_gen_subi_tl(sbit, sbit, 1);
435
        tcg_gen_and_tl(sbit, a, sbit);
edgar_igl's avatar
edgar_igl committed
436 437 438 439

        tcg_gen_andi_tl(d, cpu_PR[PR_CCS], ~(X_FLAG | N_FLAG | Z_FLAG));
	/* or in the N_FLAG.  */
        tcg_gen_or_tl(d, d, bset);
pbrook's avatar
pbrook committed
440
	tcg_gen_brcondi_tl(TCG_COND_NE, sbit, 0, l1);
edgar_igl's avatar
edgar_igl committed
441 442 443 444
	/* or in the Z_FLAG.  */
	tcg_gen_ori_tl(d, d, Z_FLAG);
	gen_set_label(l1);

445 446
        tcg_temp_free(sbit);
        tcg_temp_free(bset);
edgar_igl's avatar
edgar_igl committed
447 448
}

449
static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b)
edgar_igl's avatar
edgar_igl committed
450 451 452 453 454 455 456 457 458 459
{
	int l1;

	l1 = gen_new_label();

	/* 
	 * d <<= 1
	 * if (d >= s)
	 *    d -= s;
	 */
460 461 462
	tcg_gen_shli_tl(d, a, 1);
	tcg_gen_brcond_tl(TCG_COND_LTU, d, b, l1);
	tcg_gen_sub_tl(d, d, b);
edgar_igl's avatar
edgar_igl committed
463 464 465
	gen_set_label(l1);
}

edgar_igl's avatar
edgar_igl committed
466 467 468 469 470
/* Extended arithmetics on CRIS.  */
static inline void t_gen_add_flag(TCGv d, int flag)
{
	TCGv c;

pbrook's avatar
pbrook committed
471
	c = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
472 473 474 475 476 477
	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);
478
	tcg_temp_free(c);
edgar_igl's avatar
edgar_igl committed
479 480
}

481
static inline void t_gen_addx_carry(DisasContext *dc, TCGv d)
edgar_igl's avatar
edgar_igl committed
482
{
483 484 485 486
	if (dc->flagx_known) {
		if (dc->flags_x) {
			TCGv c;
            
pbrook's avatar
pbrook committed
487
			c = tcg_temp_new();
488 489 490 491 492 493 494 495
			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;
edgar_igl's avatar
edgar_igl committed
496

pbrook's avatar
pbrook committed
497 498
		x = tcg_temp_new();
		c = tcg_temp_new();
499 500
		t_gen_mov_TN_preg(x, PR_CCS);
		tcg_gen_mov_tl(c, x);
edgar_igl's avatar
edgar_igl committed
501

502 503 504 505
		/* 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);
edgar_igl's avatar
edgar_igl committed
506

507 508 509 510 511
		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
512 513
}

514
static inline void t_gen_subx_carry(DisasContext *dc, TCGv d)
edgar_igl's avatar
edgar_igl committed
515
{
516 517 518 519
	if (dc->flagx_known) {
		if (dc->flags_x) {
			TCGv c;
            
pbrook's avatar
pbrook committed
520
			c = tcg_temp_new();
521 522 523 524 525 526 527
			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 {
528 529
		TCGv x, c;

pbrook's avatar
pbrook committed
530 531
		x = tcg_temp_new();
		c = tcg_temp_new();
532 533 534 535 536 537 538 539 540 541
		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);
542 543
		tcg_temp_free(x);
		tcg_temp_free(c);
544
	}
edgar_igl's avatar
edgar_igl committed
545 546 547 548 549 550 551 552
}

/* 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)
{
	TCGv t, org_s;

pbrook's avatar
pbrook committed
553 554
	t = tcg_temp_new();
	org_s = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
555 556 557 558 559 560 561 562

	/* 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);
563 564
	tcg_temp_free(t);
	tcg_temp_free(org_s);
edgar_igl's avatar
edgar_igl committed
565 566 567 568 569 570 571
}

/* Swap the halfwords of the s operand.  */
static inline void t_gen_swapw(TCGv d, TCGv s)
{
	TCGv t;
	/* d and s refer the same object.  */
pbrook's avatar
pbrook committed
572
	t = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
573 574 575 576
	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);
577
	tcg_temp_free(t);
edgar_igl's avatar
edgar_igl committed
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
}

/* 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)
{
	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.  */
pbrook's avatar
pbrook committed
609 610
	t = tcg_temp_new();
	org_s = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
611 612 613 614
	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);
615
	for (i = 1; i < ARRAY_SIZE(bitrev); i++) {
edgar_igl's avatar
edgar_igl committed
616 617 618 619 620 621 622 623
		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);
	}
624 625
	tcg_temp_free(t);
	tcg_temp_free(org_s);
edgar_igl's avatar
edgar_igl committed
626 627
}

628
static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false)
edgar_igl's avatar
edgar_igl committed
629 630 631 632 633
{
	TCGv btaken;
	int l1;

	l1 = gen_new_label();
pbrook's avatar
pbrook committed
634
	btaken = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
635 636

	/* Conditional jmp.  */
edgar_igl's avatar
edgar_igl committed
637
	tcg_gen_mov_tl(btaken, env_btaken);
638
	tcg_gen_mov_tl(env_pc, pc_false);
pbrook's avatar
pbrook committed
639
	tcg_gen_brcondi_tl(TCG_COND_EQ, btaken, 0, l1);
640
	tcg_gen_mov_tl(env_pc, pc_true);
edgar_igl's avatar
edgar_igl committed
641 642
	gen_set_label(l1);

643
	tcg_temp_free(btaken);
edgar_igl's avatar
edgar_igl committed
644 645
}

646 647 648 649 650
static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
{
	TranslationBlock *tb;
	tb = dc->tb;
	if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
651
		tcg_gen_goto_tb(n);
652
		tcg_gen_movi_tl(env_pc, dest);
653
		tcg_gen_exit_tb((long)tb + n);
654
	} else {
edgar_igl's avatar
edgar_igl committed
655
		tcg_gen_movi_tl(env_pc, dest);
656
		tcg_gen_exit_tb(0);
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
	}
}

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

	/* LSL.  */
	val <<= 31 - width;
	sval = val;
	/* ASR.  */
	sval >>= 31 - width;
	return sval;
}

673 674
static inline void cris_clear_x_flag(DisasContext *dc)
{
edgar_igl's avatar
edgar_igl committed
675 676 677
	if (dc->flagx_known && dc->flags_x)
		dc->flags_uptodate = 0;

678
	dc->flagx_known = 1;
edgar_igl's avatar
edgar_igl committed
679
	dc->flags_x = 0;
680 681
}

682
static void cris_flush_cc_state(DisasContext *dc)
683
{
684
	if (dc->cc_size_uptodate != dc->cc_size) {
edgar_igl's avatar
edgar_igl committed
685
		tcg_gen_movi_tl(cc_size, dc->cc_size);
686 687 688 689 690 691 692 693 694 695
		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);
}

static void cris_evaluate_flags(DisasContext *dc)
{
	if (!dc->flags_uptodate) {
		cris_flush_cc_state(dc);
edgar_igl's avatar
edgar_igl committed
696

697 698 699
		switch (dc->cc_op)
		{
			case CC_OP_MCP:
pbrook's avatar
pbrook committed
700
				gen_helper_evaluate_flags_mcp();
701 702
				break;
			case CC_OP_MULS:
pbrook's avatar
pbrook committed
703
				gen_helper_evaluate_flags_muls();
704 705
				break;
			case CC_OP_MULU:
pbrook's avatar
pbrook committed
706
				gen_helper_evaluate_flags_mulu();
707 708
				break;
			case CC_OP_MOVE:
709 710 711 712 713 714
			case CC_OP_AND:
			case CC_OP_OR:
			case CC_OP_XOR:
			case CC_OP_ASR:
			case CC_OP_LSR:
			case CC_OP_LSL:
715 716 717
				switch (dc->cc_size)
				{
					case 4:
pbrook's avatar
pbrook committed
718
						gen_helper_evaluate_flags_move_4();
719 720
						break;
					case 2:
pbrook's avatar
pbrook committed
721
						gen_helper_evaluate_flags_move_2();
722 723
						break;
					default:
pbrook's avatar
pbrook committed
724
						gen_helper_evaluate_flags();
725 726 727
						break;
				}
				break;
edgar_igl's avatar
edgar_igl committed
728 729 730
			case CC_OP_FLAGS:
				/* live.  */
				break;
731 732 733 734 735
			default:
			{
				switch (dc->cc_size)
				{
					case 4:
pbrook's avatar
pbrook committed
736
						gen_helper_evaluate_flags_alu_4();
737 738
						break;
					default:
pbrook's avatar
pbrook committed
739
						gen_helper_evaluate_flags();
740 741 742 743 744
						break;
				}
			}
			break;
		}
edgar_igl's avatar
edgar_igl committed
745 746 747 748 749 750 751
		if (dc->flagx_known) {
			if (dc->flags_x)
				tcg_gen_ori_tl(cpu_PR[PR_CCS], 
					       cpu_PR[PR_CCS], X_FLAG);
			else
				tcg_gen_andi_tl(cpu_PR[PR_CCS], 
						cpu_PR[PR_CCS], ~X_FLAG);
edgar_igl's avatar
edgar_igl committed
752
	        }
edgar_igl's avatar
edgar_igl committed
753

754
		dc->flags_uptodate = 1;
755 756 757 758 759 760 761
	}
}

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

edgar_igl's avatar
edgar_igl committed
762 763 764 765 766
	if (!mask) {
		dc->update_cc = 0;
		return;
	}	

767 768
	/* Check if we need to evaluate the condition codes due to 
	   CC overlaying.  */
769 770 771 772 773 774 775 776 777
	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;
}

edgar_igl's avatar
edgar_igl committed
778
static void cris_update_cc_op(DisasContext *dc, int op, int size)
779 780 781
{
	dc->cc_op = op;
	dc->cc_size = size;
782
	dc->flags_uptodate = 0;
783 784
}

785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
static inline void cris_update_cc_x(DisasContext *dc)
{
	/* 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;
	}
}

/* Update cc prior to executing ALU op. Needs source operands untouched.  */
static void cris_pre_alu_update_cc(DisasContext *dc, int op, 
				   TCGv dst, TCGv src, int size)
803 804
{
	if (dc->update_cc) {
edgar_igl's avatar
edgar_igl committed
805
		cris_update_cc_op(dc, op, size);
806 807 808 809 810 811 812 813 814 815 816 817 818 819
		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);

		cris_update_cc_x(dc);
	}
}
edgar_igl's avatar
edgar_igl committed
820

821 822 823 824 825 826 827 828 829
/* Update cc after executing ALU op. needs the result.  */
static inline void cris_update_result(DisasContext *dc, TCGv res)
{
	if (dc->update_cc) {
		if (dc->cc_size == 4 && 
		    (dc->cc_op == CC_OP_SUB
		     || dc->cc_op == CC_OP_ADD))
			return;
		tcg_gen_mov_tl(cc_result, res);
830
	}
831
}
832

833 834 835 836
/* Returns one if the write back stage should execute.  */
static void cris_alu_op_exec(DisasContext *dc, int op, 
			       TCGv dst, TCGv a, TCGv b, int size)
{
837 838 839 840
	/* Emit the ALU insns.  */
	switch (op)
	{
		case CC_OP_ADD:
841
			tcg_gen_add_tl(dst, a, b);
842
			/* Extended arithmetics.  */
843
			t_gen_addx_carry(dc, dst);
844 845
			break;
		case CC_OP_ADDC:
846 847
			tcg_gen_add_tl(dst, a, b);
			t_gen_add_flag(dst, 0); /* C_FLAG.  */
848 849
			break;
		case CC_OP_MCP:
850 851
			tcg_gen_add_tl(dst, a, b);
			t_gen_add_flag(dst, 8); /* R_FLAG.  */
852 853
			break;
		case CC_OP_SUB:
854
			tcg_gen_sub_tl(dst, a, b);
855
			/* Extended arithmetics.  */
856
			t_gen_subx_carry(dc, dst);
857 858
			break;
		case CC_OP_MOVE:
859
			tcg_gen_mov_tl(dst, b);
860 861
			break;
		case CC_OP_OR:
862
			tcg_gen_or_tl(dst, a, b);
863 864
			break;
		case CC_OP_AND:
865
			tcg_gen_and_tl(dst, a, b);
866 867
			break;
		case CC_OP_XOR:
868
			tcg_gen_xor_tl(dst, a, b);
869 870
			break;
		case CC_OP_LSL:
871
			t_gen_lsl(dst, a, b);
872 873
			break;
		case CC_OP_LSR:
874
			t_gen_lsr(dst, a, b);
875 876
			break;
		case CC_OP_ASR:
877
			t_gen_asr(dst, a, b);
878 879
			break;
		case CC_OP_NEG:
880
			tcg_gen_neg_tl(dst, b);
881
			/* Extended arithmetics.  */
882
			t_gen_subx_carry(dc, dst);
883 884
			break;
		case CC_OP_LZ:
885
			t_gen_lz_i32(dst, b);
886 887
			break;
		case CC_OP_BTST:
888
			t_gen_btst(dst, a, b);
889 890
			break;
		case CC_OP_MULS:
891 892
			t_gen_muls(dst, cpu_PR[PR_MOF], a, b);
			break;
893
		case CC_OP_MULU:
894 895
			t_gen_mulu(dst, cpu_PR[PR_MOF], a, b);
			break;
896
		case CC_OP_DSTEP:
897
			t_gen_cris_dstep(dst, a, b);
898 899
			break;
		case CC_OP_BOUND:
edgar_igl's avatar
edgar_igl committed
900 901 902
		{
			int l1;
			l1 = gen_new_label();
903 904 905
			tcg_gen_mov_tl(dst, a);
			tcg_gen_brcond_tl(TCG_COND_LEU, a, b, l1);
			tcg_gen_mov_tl(dst, b);
edgar_igl's avatar
edgar_igl committed
906 907 908
			gen_set_label(l1);
		}
		break;
909
		case CC_OP_CMP:
910
			tcg_gen_sub_tl(dst, a, b);
911
			/* Extended arithmetics.  */
912
			t_gen_subx_carry(dc, dst);
913 914 915 916 917 918 919 920
			break;
		default:
			fprintf (logfile, "illegal ALU op.\n");
			BUG();
			break;
	}

	if (size == 1)
921
		tcg_gen_andi_tl(dst, dst, 0xff);
922
	else if (size == 2)
923 924 925 926 927 928 929 930 931 932
		tcg_gen_andi_tl(dst, dst, 0xffff);
}

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

	writeback = 1;
edgar_igl's avatar
edgar_igl committed
933 934

	if (op == CC_OP_BOUND || op == CC_OP_BTST)
pbrook's avatar
pbrook committed
935
		tmp = tcg_temp_local_new();
edgar_igl's avatar
edgar_igl committed
936 937

	if (op == CC_OP_CMP) {
pbrook's avatar
pbrook committed
938
		tmp = tcg_temp_new();
939
		writeback = 0;
edgar_igl's avatar
edgar_igl committed
940
	} else if (size == 4) {
941 942
		tmp = d;
		writeback = 0;
edgar_igl's avatar
edgar_igl committed
943
	} else
pbrook's avatar
pbrook committed
944
		tmp = tcg_temp_new();
edgar_igl's avatar
edgar_igl committed
945

946 947 948 949

	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);
950

951 952
	/* Writeback.  */
	if (writeback) {
953 954 955 956 957
		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);
958
	}
pbrook's avatar
pbrook committed
959
	if (!TCGV_EQUAL(tmp, d))
edgar_igl's avatar
edgar_igl committed
960
		tcg_temp_free(tmp);
961 962 963 964 965 966
}

static int arith_cc(DisasContext *dc)
{
	if (dc->update_cc) {
		switch (dc->cc_op) {
967
			case CC_OP_ADDC: return 1;
968 969
			case CC_OP_ADD: return 1;
			case CC_OP_SUB: return 1;
970
			case CC_OP_DSTEP: return 1;
971 972 973 974
			case CC_OP_LSL: return 1;
			case CC_OP_LSR: return 1;
			case CC_OP_ASR: return 1;
			case CC_OP_CMP: return 1;
975 976 977 978 979
			case CC_OP_NEG: return 1;
			case CC_OP_OR: return 1;
			case CC_OP_XOR: return 1;
			case CC_OP_MULU: return 1;
			case CC_OP_MULS: return 1;
980 981 982 983 984 985 986
			default:
				return 0;
		}
	}
	return 0;
}

987
static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
988
{
edgar_igl's avatar
edgar_igl committed
989
	int arith_opt, move_opt;
990 991

	/* TODO: optimize more condition codes.  */
edgar_igl's avatar
edgar_igl committed
992 993 994 995 996 997 998 999 1000

	/*
	 * 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.
	 */
1001
	arith_opt = arith_cc(dc) && !dc->flags_uptodate;
1002
	move_opt = (dc->cc_op == CC_OP_MOVE) && dc->flags_uptodate;
1003 1004
	switch (cond) {
		case CC_EQ:
edgar_igl's avatar
edgar_igl committed
1005
			if (arith_opt || move_opt) {
edgar_igl's avatar
edgar_igl committed
1006 1007 1008 1009
				/* If cc_result is zero, T0 should be 
				   non-zero otherwise T0 should be zero.  */
				int l1;
				l1 = gen_new_label();
1010
				tcg_gen_movi_tl(cc, 0);
pbrook's avatar
pbrook committed
1011 1012
				tcg_gen_brcondi_tl(TCG_COND_NE, cc_result, 
						   0, l1);
1013
				tcg_gen_movi_tl(cc, 1);
edgar_igl's avatar
edgar_igl committed
1014 1015
				gen_set_label(l1);
			}
1016 1017
			else {
				cris_evaluate_flags(dc);
1018
				tcg_gen_andi_tl(cc, 
edgar_igl's avatar
edgar_igl committed
1019
						cpu_PR[PR_CCS], Z_FLAG);
1020 1021 1022
			}
			break;
		case CC_NE:
edgar_igl's avatar
edgar_igl committed
1023
			if (arith_opt || move_opt)
1024
				tcg_gen_mov_tl(cc, cc_result);
1025 1026
			else {
				cris_evaluate_flags(dc);
1027
				tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
edgar_igl's avatar
edgar_igl committed
1028
						Z_FLAG);
1029
				tcg_gen_andi_tl(cc, cc, Z_FLAG);
1030 1031 1032 1033
			}
			break;
		case CC_CS:
			cris_evaluate_flags(dc);
1034
			tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], C_FLAG);
1035 1036 1037
			break;
		case CC_CC:
			cris_evaluate_flags(dc);
1038 1039
			tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], C_FLAG);
			tcg_gen_andi_tl(cc, cc, C_FLAG);
1040 1041 1042
			break;
		case CC_VS:
			cris_evaluate_flags(dc);
1043
			tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], V_FLAG);
1044 1045 1046
			break;
		case CC_VC:
			cris_evaluate_flags(dc);
1047
			tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
edgar_igl's avatar
edgar_igl committed
1048
					V_FLAG);
1049
			tcg_gen_andi_tl(cc, cc, V_FLAG);
1050 1051
			break;
		case CC_PL:
edgar_igl's avatar
edgar_igl committed
1052 1053 1054 1055 1056 1057 1058 1059
			if (arith_opt || move_opt) {
				int bits = 31;

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

1060 1061
				tcg_gen_shri_tl(cc, cc_result, bits);
				tcg_gen_xori_tl(cc, cc, 1);
edgar_igl's avatar
edgar_igl committed
1062
			} else {
1063
				cris_evaluate_flags(dc);
1064
				tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
edgar_igl's avatar
edgar_igl committed
1065
						N_FLAG);
1066
				tcg_gen_andi_tl(cc, cc, N_FLAG);
1067 1068 1069
			}
			break;
		case CC_MI:
edgar_igl's avatar
edgar_igl committed
1070 1071 1072 1073 1074 1075 1076