diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 9b3bf7a448..60f88e6bc9 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -456,8 +456,6 @@ typedef enum {
 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector);
 void m68k_switch_sp(CPUM68KState *env);
 
-void do_m68k_semihosting(CPUM68KState *env, int nr);
-
 /*
  * The 68000 family is defined in six main CPU classes, the 680[012346]0.
  * Generally each successive CPU adds enhanced data/stack/instructions.
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 0a6b4146f6..0e27c27810 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -128,4 +128,5 @@ DEF_HELPER_4(chk2, void, env, s32, s32, s32)
 DEF_HELPER_3(ptest, void, env, i32, i32)
 DEF_HELPER_3(pflush, void, env, i32, i32)
 DEF_HELPER_FLAGS_1(reset, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_1(semihosting, void, env)
 #endif
diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 71f9d42e6c..1a36c1158d 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -25,6 +25,7 @@
 #include "semihosting/softmmu-uaccess.h"
 #include "hw/boards.h"
 #include "qemu/log.h"
+#include "exec/helper-proto.h"
 
 #define HOSTED_EXIT  0
 #define HOSTED_INIT_SIM 1
@@ -84,12 +85,13 @@ static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err)
     }                                                   \
 } while (0)
 
-void do_m68k_semihosting(CPUM68KState *env, int nr)
+void HELPER(semihosting)(CPUM68KState *env)
 {
     CPUState *cs = env_cpu(env);
-    uint32_t args;
+    uint32_t args, nr;
     target_ulong arg0, arg1, arg2, arg3;
 
+    nr = env->dregs[0];
     args = env->dregs[1];
     switch (nr) {
     case HOSTED_EXIT:
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index 8decc61240..a345245612 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -22,7 +22,6 @@
 #include "exec/helper-proto.h"
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
-#include "semihosting/semihost.h"
 
 #if !defined(CONFIG_USER_ONLY)
 
@@ -203,15 +202,6 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw)
             cf_rte(env);
             return;
         case EXCP_HALT_INSN:
-            if (semihosting_enabled()
-                    && (env->sr & SR_S) != 0
-                    && (env->pc & 3) == 0
-                    && cpu_lduw_code(env, env->pc - 4) == 0x4e71
-                    && cpu_ldl_code(env, env->pc) == 0x4e7bf000) {
-                env->pc += 4;
-                do_m68k_semihosting(env, env->dregs[0]);
-                return;
-            }
             cs->halted = 1;
             cs->exception_index = EXCP_HLT;
             cpu_loop_exit(cs);
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 4026572ed8..b7adc8f53d 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -33,6 +33,9 @@
 
 #include "exec/log.h"
 #include "fpu/softfloat.h"
+#ifndef CONFIG_USER_ONLY
+#include "semihosting/semihost.h"
+#endif
 
 
 //#define DEBUG_DISPATCH 1
@@ -313,6 +316,25 @@ static inline void gen_addr_fault(DisasContext *s)
     gen_exception(s, s->base.pc_next, EXCP_ADDRESS);
 }
 
+#ifndef CONFIG_USER_ONLY
+static bool maybe_semihosting(DisasContext *s)
+{
+    /*
+     * The semihosting insn (halt or bkpt) is preceeded by an aligned NOP
+     * and followed by an invalid sentinel insn (movec %sp,0).
+     */
+    if (semihosting_enabled()
+        && (s->pc & 3) == 2
+        && cpu_lduw_code(s->env, s->pc - 2) == 0x4e71
+        && cpu_ldl_code(s->env, s->pc + 4) == 0x4e7bf000) {
+        gen_helper_semihosting(cpu_env);
+        s->pc += 4;
+        return true;
+    }
+    return false;
+}
+#endif
+
 /*
  * Generate a load from the specified address.  Narrow values are
  *  sign extended to full register width.
@@ -4702,7 +4724,9 @@ DISAS_INSN(halt)
         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
         return;
     }
-
+    if (maybe_semihosting(s)) {
+        return;
+    }
     gen_exception(s, s->pc, EXCP_HALT_INSN);
 }
 
