summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--target-cris/helper.h1
-rw-r--r--target-cris/op_helper.c108
-rw-r--r--target-cris/translate.c26
3 files changed, 76 insertions, 59 deletions
diff --git a/target-cris/helper.h b/target-cris/helper.h
index 9034a6157e..e4684397a0 100644
--- a/target-cris/helper.h
+++ b/target-cris/helper.h
@@ -14,6 +14,7 @@ DEF_HELPER_0(evaluate_flags_muls, void)
 DEF_HELPER_0(evaluate_flags_mulu, void)
 DEF_HELPER_0(evaluate_flags_mcp, void)
 DEF_HELPER_0(evaluate_flags_alu_4, void)
+DEF_HELPER_0(evaluate_flags_sub_4, void)
 DEF_HELPER_0(evaluate_flags_move_4, void)
 DEF_HELPER_0(evaluate_flags_move_2, void)
 DEF_HELPER_0(evaluate_flags, void)
diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c
index 5db4575fe5..51323a2a5c 100644
--- a/target-cris/op_helper.c
+++ b/target-cris/op_helper.c
@@ -245,17 +245,19 @@ void helper_rfn(void)
 
 static void evaluate_flags_writeback(uint32_t flags)
 {
-	int x;
+	unsigned int x, z, mask;
 
 	/* Extended arithmetics, leave the z flag alone.  */
 	x = env->cc_x;
-	if ((x || env->cc_op == CC_OP_ADDC)
-	    && flags & Z_FLAG)
-		env->cc_mask &= ~Z_FLAG;
+	mask = env->cc_mask | X_FLAG;
+        if (x) {
+		z = flags & Z_FLAG;
+		mask = mask & ~z;
+	}
+	flags &= mask;
 
 	/* all insn clear the x-flag except setf or clrf.  */
-	env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
-	flags &= env->cc_mask;
+	env->pregs[PR_CCS] &= ~mask;
 	env->pregs[PR_CCS] |= flags;
 }
 
@@ -323,33 +325,25 @@ void  helper_evaluate_flags_mcp(void)
 	uint32_t res;
 	uint32_t flags = 0;
 
-	src = env->cc_src;
-	dst = env->cc_dest;
+	src = env->cc_src & 0x80000000;
+	dst = env->cc_dest & 0x80000000;
 	res = env->cc_result;
 
 	if ((res & 0x80000000L) != 0L)
 	{
 		flags |= N_FLAG;
-		if (((src & 0x80000000L) == 0L)
-		    && ((dst & 0x80000000L) == 0L))
-		{
+		if (!src && !dst)
 			flags |= V_FLAG;
-		}
-		else if (((src & 0x80000000L) != 0L) &&
-			 ((dst & 0x80000000L) != 0L))
-		{
+		else if (src & dst)
 			flags |= R_FLAG;
-		}
 	}
 	else
 	{
 		if (res == 0L)
 			flags |= Z_FLAG;
-		if (((src & 0x80000000L) != 0L)
-		    && ((dst & 0x80000000L) != 0L))
+		if (src & dst) 
 			flags |= V_FLAG;
-		if ((dst & 0x80000000L) != 0L
-		    || (src & 0x80000000L) != 0L)
+		if (dst | src) 
 			flags |= R_FLAG;
 	}
 
@@ -363,56 +357,61 @@ void  helper_evaluate_flags_alu_4(void)
 	uint32_t res;
 	uint32_t flags = 0;
 
-	src = env->cc_src;
-	dst = env->cc_dest;
+	src = env->cc_src & 0x80000000;
+	dst = env->cc_dest & 0x80000000;
+	res = env->cc_result;
 
-	/* Reconstruct the result.  */
-	switch (env->cc_op)
+	if ((res & 0x80000000L) != 0L)
 	{
-		case CC_OP_SUB:
-			res = dst - src;
-			break;
-		case CC_OP_ADD:
-			res = dst + src;
-			break;
-		default:
-			res = env->cc_result;
-			break;
+		flags |= N_FLAG;
+		if (!src && !dst)
+			flags |= V_FLAG;
+		else if (src & dst)
+			flags |= C_FLAG;
+	}
+	else
+	{
+		if (res == 0L)
+			flags |= Z_FLAG;
+		if (src & dst) 
+			flags |= V_FLAG;
+		if (dst | src) 
+			flags |= C_FLAG;
 	}
 
-	if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
-		src = ~src;
+	evaluate_flags_writeback(flags);
+}
+
+void  helper_evaluate_flags_sub_4(void)
+{
+	uint32_t src;
+	uint32_t dst;
+	uint32_t res;
+	uint32_t flags = 0;
+
+	src = (~env->cc_src) & 0x80000000;
+	dst = env->cc_dest & 0x80000000;
+	res = env->cc_result;
 
 	if ((res & 0x80000000L) != 0L)
 	{
 		flags |= N_FLAG;
-		if (((src & 0x80000000L) == 0L)
-		    && ((dst & 0x80000000L) == 0L))
-		{
+		if (!src && !dst)
 			flags |= V_FLAG;
-		}
-		else if (((src & 0x80000000L) != 0L) &&
-			 ((dst & 0x80000000L) != 0L))
-		{
+		else if (src & dst)
 			flags |= C_FLAG;
-		}
 	}
 	else
 	{
 		if (res == 0L)
 			flags |= Z_FLAG;
-		if (((src & 0x80000000L) != 0L)
-		    && ((dst & 0x80000000L) != 0L))
+		if (src & dst) 
 			flags |= V_FLAG;
-		if ((dst & 0x80000000L) != 0L
-		    || (src & 0x80000000L) != 0L)
+		if (dst | src) 
 			flags |= C_FLAG;
 	}
 
-	if (env->cc_op == CC_OP_SUB
-	    || env->cc_op == CC_OP_CMP) {
-		flags ^= C_FLAG;
-	}
+	flags ^= C_FLAG;
 	evaluate_flags_writeback(flags);
 }
 
@@ -607,6 +606,13 @@ void helper_top_evaluate_flags(void)
 		case CC_OP_FLAGS:
 			/* live.  */
 			break;
+		case CC_OP_SUB:
+		case CC_OP_CMP:
+			if (env->cc_size == 4)
+				helper_evaluate_flags_sub_4();
+			else
+				helper_evaluate_flags();
+			break;
 		default:
 		{
 			switch (env->cc_size)
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 6a8c355975..24ae03cfac 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -728,8 +728,15 @@ static void cris_evaluate_flags(DisasContext *dc)
 			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();
+				else
+					gen_helper_evaluate_flags();
+
+				break;
 			default:
-			{
 				switch (dc->cc_size)
 				{
 					case 4:
@@ -739,7 +746,6 @@ static void cris_evaluate_flags(DisasContext *dc)
 						gen_helper_evaluate_flags();
 						break;
 				}
-			}
 			break;
 		}
 		if (dc->flagx_known) {
@@ -821,13 +827,8 @@ static void cris_pre_alu_update_cc(DisasContext *dc, int op,
 /* 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;
+	if (dc->update_cc)
 		tcg_gen_mov_tl(cc_result, res);
-	}
 }
 
 /* Returns one if the write back stage should execute.  */
@@ -1890,6 +1891,10 @@ static unsigned int dec_addc_r(DisasContext *dc)
 	DIS(fprintf (logfile, "addc $r%u, $r%u\n",
 		    dc->op1, dc->op2));
 	cris_evaluate_flags(dc);
+	/* Set for this insn.  */
+	dc->flagx_known = 1;
+	dc->flags_x = X_FLAG;
+
 	cris_cc_mask(dc, CC_MASK_NZVC);
 	cris_alu(dc, CC_OP_ADDC,
 		 cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4);
@@ -2615,6 +2620,11 @@ static unsigned int dec_addc_mr(DisasContext *dc)
 		    dc->op2));
 
 	cris_evaluate_flags(dc);
+
+	/* Set for this insn.  */
+	dc->flagx_known = 1;
+	dc->flags_x = X_FLAG;
+
 	cris_alu_m_alloc_temps(t);
 	insn_len = dec_prep_alu_m(dc, 0, 4, t[0], t[1]);
 	cris_cc_mask(dc, CC_MASK_NZVC);