aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/arm/translate.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 3fb378a..65df8d6 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -11624,7 +11624,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
imm = -imm;
/* Fall through. */
case 0xf: /* Pre-increment. */
- tcg_gen_addi_i32(addr, addr, imm);
writeback = 1;
break;
default:
@@ -11636,6 +11635,28 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
issinfo = writeback ? ISSInvalid : rs;
+ if (s->v8m_stackcheck && rn == 13 && writeback) {
+ /*
+ * Stackcheck. Here we know 'addr' is the current SP;
+ * if imm is +ve we're moving SP up, else down. It is
+ * UNKNOWN whether the limit check triggers when SP starts
+ * below the limit and ends up above it; we chose to do so.
+ */
+ if ((int32_t)imm < 0) {
+ TCGv_i32 newsp = tcg_temp_new_i32();
+
+ tcg_gen_addi_i32(newsp, addr, imm);
+ gen_helper_v8m_stackcheck(cpu_env, newsp);
+ tcg_temp_free_i32(newsp);
+ } else {
+ gen_helper_v8m_stackcheck(cpu_env, addr);
+ }
+ }
+
+ if (writeback && !postinc) {
+ tcg_gen_addi_i32(addr, addr, imm);
+ }
+
if (insn & (1 << 20)) {
/* Load. */
tmp = tcg_temp_new_i32();