summary refs log tree commit diff stats
path: root/target-cris/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-cris/translate.c')
-rw-r--r--target-cris/translate.c162
1 files changed, 132 insertions, 30 deletions
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 91e3972e1a..f8baa88c18 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -86,6 +86,7 @@ typedef struct DisasContext {
 	target_ulong pc, ppc;
 
 	/* Decoder.  */
+	unsigned int (*decoder)(struct DisasContext *dc);
 	uint32_t ir;
 	uint32_t opcode;
 	unsigned int op1;
@@ -94,6 +95,11 @@ typedef struct DisasContext {
 	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;
@@ -108,6 +114,8 @@ typedef struct DisasContext {
 	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;
@@ -219,6 +227,12 @@ static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn)
 	}
 }
 
+static void cris_lock_irq(DisasContext *dc)
+{
+	dc->clear_locked_irq = 0;
+	t_gen_mov_env_TN(locked_irq, tcg_const_tl(1));
+}
+
 static inline void t_gen_raise_exception(uint32_t index)
 {
         TCGv_i32 tmp = tcg_const_i32(index);
@@ -332,6 +346,24 @@ static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b)
 	gen_set_label(l1);
 }
 
+static void t_gen_cris_mstep(TCGv d, TCGv a, TCGv b, TCGv ccs)
+{
+	TCGv t;
+
+	/* 
+	 * 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);
+}
+
 /* Extended arithmetics on CRIS.  */
 static inline void t_gen_add_flag(TCGv d, int flag)
 {
@@ -634,7 +666,7 @@ static void cris_evaluate_flags(DisasContext *dc)
 		if (dc->flags_x)
 			tcg_gen_ori_tl(cpu_PR[PR_CCS], 
 				       cpu_PR[PR_CCS], X_FLAG);
-		else
+		else if (dc->cc_op == CC_OP_FLAGS)
 			tcg_gen_andi_tl(cpu_PR[PR_CCS], 
 					cpu_PR[PR_CCS], ~X_FLAG);
         }
@@ -774,6 +806,9 @@ static void cris_alu_op_exec(DisasContext *dc, int op,
 		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;
@@ -878,7 +913,8 @@ static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
 	move_opt = (dc->cc_op == CC_OP_MOVE);
 	switch (cond) {
 		case CC_EQ:
-			if (arith_opt || move_opt) {
+			if ((arith_opt || move_opt)
+			    && dc->cc_x_uptodate != (2 | X_FLAG)) {
 				/* If cc_result is zero, T0 should be 
 				   non-zero otherwise T0 should be zero.  */
 				int l1;
@@ -896,9 +932,10 @@ static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
 			}
 			break;
 		case CC_NE:
-			if (arith_opt || move_opt)
+			if ((arith_opt || move_opt)
+			    && dc->cc_x_uptodate != (2 | X_FLAG)) {
 				tcg_gen_mov_tl(cc, cc_result);
-			else {
+	 		} else {
 				cris_evaluate_flags(dc);
 				tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
 						Z_FLAG);
@@ -2058,16 +2095,17 @@ static unsigned int dec_setclrf(DisasContext *dc)
 			dc->flags_x = 0;
 	}
 
-	/* Break the TB if the P flag changes.  */
-	if (flags & P_FLAG) {
-		if ((set && !(dc->tb_flags & P_FLAG))
-		    || (!set && (dc->tb_flags & P_FLAG))) {
-			tcg_gen_movi_tl(env_pc, dc->pc + 2);
-			dc->is_jmp = DISAS_UPDATE;
-			dc->cpustate_changed = 1;
-		}
+	/* Break the TB if any of the SPI flag changes.  */
+	if (flags & (P_FLAG | S_FLAG)) {
+		tcg_gen_movi_tl(env_pc, dc->pc + 2);
+		dc->is_jmp = DISAS_UPDATE;
+		dc->cpustate_changed = 1;
 	}
-	if (flags & S_FLAG) {
+
+	/* For the I flag, only act on posedge.  */
+	if ((flags & I_FLAG)) {
+		tcg_gen_movi_tl(env_pc, dc->pc + 2);
+		dc->is_jmp = DISAS_UPDATE;
 		dc->cpustate_changed = 1;
 	}
 
@@ -2143,17 +2181,22 @@ static unsigned int dec_move_rp(DisasContext *dc)
 static unsigned int dec_move_pr(DisasContext *dc)
 {
 	TCGv t0;
-	LOG_DIS("move $p%u, $r%u\n", dc->op1, dc->op2);
+	LOG_DIS("move $p%u, $r%u\n", dc->op2, dc->op1);
 	cris_cc_mask(dc, 0);
 
 	if (dc->op2 == PR_CCS)
 		cris_evaluate_flags(dc);
 
-	t0 = tcg_temp_new();
-	t_gen_mov_TN_preg(t0, dc->op2);
-	cris_alu(dc, CC_OP_MOVE,
-		 cpu_R[dc->op1], cpu_R[dc->op1], t0, preg_sizes[dc->op2]);
-	tcg_temp_free(t0);
+        if (dc->op2 == PR_DZ) {
+		tcg_gen_movi_tl(cpu_R[dc->op1], 0);
+        } else {
+		t0 = tcg_temp_new();
+		t_gen_mov_TN_preg(t0, dc->op2);
+		cris_alu(dc, CC_OP_MOVE,
+			 cpu_R[dc->op1], cpu_R[dc->op1], t0,
+			 preg_sizes[dc->op2]);
+		tcg_temp_free(t0);
+	}
 	return 2;
 }
 
@@ -3026,8 +3069,7 @@ static struct decoder_info {
 	{{0, 0}, dec_null}
 };
 
-static inline unsigned int
-cris_decoder(DisasContext *dc)
+static unsigned int crisv32_decoder(DisasContext *dc)
 {
 	unsigned int insn_len = 2;
 	int i;
@@ -3090,6 +3132,7 @@ static void check_breakpoint(CPUState *env, DisasContext *dc)
 	}
 }
 
+#include "translate_v10.c"
 
 /*
  * Delay slots on QEMU/CRIS.
@@ -3132,7 +3175,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 {
 	uint16_t *gen_opc_end;
    	uint32_t pc_start;
-	unsigned int insn_len;
+	unsigned int insn_len, orig_flags;
 	int j, lj;
 	struct DisasContext ctx;
 	struct DisasContext *dc = &ctx;
@@ -3143,6 +3186,11 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 
 	qemu_log_try_set_file(stderr);
 
+	if (env->pregs[PR_VR] == 32)
+		dc->decoder = crisv32_decoder;
+	else
+		dc->decoder = crisv10_decoder;
+
 	/* Odd PC indicates that branch is rexecuting due to exception in the
 	 * delayslot, like in real hw.
 	 */
@@ -3162,12 +3210,15 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 	dc->cc_x_uptodate = 0;
 	dc->cc_mask = 0;
 	dc->update_cc = 0;
+	dc->clear_prefix = 0;
+	dc->clear_locked_irq = 1;
 
 	cris_update_cc_op(dc, CC_OP_FLAGS, 4);
 	dc->cc_size_uptodate = -1;
 
 	/* Decode TB flags.  */
-	dc->tb_flags = tb->flags & (S_FLAG | P_FLAG | U_FLAG | X_FLAG);
+	orig_flags = dc->tb_flags = tb->flags & (S_FLAG | P_FLAG | U_FLAG \
+					| X_FLAG | PFIX_FLAG);
 	dc->delayed_branch = !!(tb->flags & 7);
 	if (dc->delayed_branch)
 		dc->jmp = JMP_INDIRECT;
@@ -3233,7 +3284,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
                     gen_io_start();
 		dc->clear_x = 1;
 
-		insn_len = cris_decoder(dc);		
+		insn_len = dc->decoder(dc);
 		dc->ppc = dc->pc;
 		dc->pc += insn_len;
 		if (dc->clear_x)
@@ -3271,6 +3322,13 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 		 && (dc->pc < next_page_start)
                  && num_insns < max_insns);
 
+	if (dc->tb_flags != orig_flags) {
+		dc->cpustate_changed = 1;
+	}
+
+	if (dc->clear_locked_irq)
+		t_gen_mov_env_TN(locked_irq, tcg_const_tl(0));
+
 	npc = dc->pc;
 	if (dc->jmp == JMP_DIRECT && !dc->delayed_branch)
 		npc = dc->jmp_pc;
@@ -3330,7 +3388,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 #ifdef DEBUG_DISAS
 #if !DISAS_CRIS
 	if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
-		log_target_disas(pc_start, dc->pc - pc_start, 0);
+		log_target_disas(pc_start, dc->pc - pc_start,
+                                 dc->env->pregs[PR_VR]);
 		qemu_log("\nisize=%d osize=%zd\n",
 			dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
 	}
@@ -3390,6 +3449,39 @@ void cpu_dump_state (CPUState *env, FILE *f,
 
 }
 
+struct
+{
+    uint32_t vr;
+    const char *name;
+} cris_cores[] = {
+	{8, "crisv8"},
+	{9, "crisv9"},
+	{10, "crisv10"},
+	{11, "crisv11"},
+	{32, "crisv32"},
+};
+
+void cris_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+    unsigned int i;
+
+    (*cpu_fprintf)(f, "Available CPUs:\n");
+    for (i = 0; i < ARRAY_SIZE(cris_cores); i++) {
+        (*cpu_fprintf)(f, "  %s\n", cris_cores[i].name);
+    }
+}
+
+static uint32_t vr_by_name(const char *name)
+{
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(cris_cores); i++) {
+        if (strcmp(name, cris_cores[i].name) == 0) {
+            return cris_cores[i].vr;
+        }
+    }
+    return 32;
+}
+
 CPUCRISState *cpu_cris_init (const char *cpu_model)
 {
 	CPUCRISState *env;
@@ -3398,6 +3490,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
 
 	env = qemu_mallocz(sizeof(CPUCRISState));
 
+	env->pregs[PR_VR] = vr_by_name(cpu_model);
 	cpu_exec_init(env);
 	cpu_reset(env);
 	qemu_init_vcpu(env);
@@ -3407,6 +3500,15 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
 
 	tcg_initialized = 1;
 
+#define GEN_HELPER 2
+#include "helper.h"
+
+	if (env->pregs[PR_VR] < 32) {
+		cpu_crisv10_init(env);
+		return env; 
+	}
+
+
 	cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
 	cc_x = tcg_global_mem_new(TCG_AREG0,
 				  offsetof(CPUState, cc_x), "cc_x");
@@ -3447,26 +3549,26 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
 					       pregnames[i]);
 	}
 
-#define GEN_HELPER 2
-#include "helper.h"
-
 	return env;
 }
 
 void cpu_reset (CPUCRISState *env)
 {
+	uint32_t vr;
+
 	if (qemu_loglevel_mask(CPU_LOG_RESET)) {
 		qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
 		log_cpu_state(env, 0);
 	}
 
+	vr = env->pregs[PR_VR];
 	memset(env, 0, offsetof(CPUCRISState, breakpoints));
+	env->pregs[PR_VR] = vr;
 	tlb_flush(env, 1);
 
-	env->pregs[PR_VR] = 32;
 #if defined(CONFIG_USER_ONLY)
 	/* start in user mode with interrupts enabled.  */
-	env->pregs[PR_CCS] |= U_FLAG | I_FLAG;
+	env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
 #else
 	cris_mmu_init(env);
 	env->pregs[PR_CCS] = 0;