diff mbox series

[4/4] target/m68k: implement m68k "any instruction" trace mode

Message ID 20210519142917.16693-5-mark.cave-ayland@ilande.co.uk (mailing list archive)
State New, archived
Headers show
Series target/m68k: implement m68k "any instruction" trace mode | expand

Commit Message

Mark Cave-Ayland May 19, 2021, 2:29 p.m. UTC
The m68k trace mode is controlled by the top 2 bits in the SR register. Implement
the m68k "any instruction" trace mode where bit T1=1 and bit T0=0 in which the CPU
generates an EXCP_TRACE exception (vector 9 or offset 0x24) after executing each
instruction.

This functionality is used by the NetBSD kernel debugger to allow single-stepping
on m68k architectures.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 target/m68k/cpu.h       |  8 ++++++++
 target/m68k/translate.c | 27 ++++++++++++++++++++-------
 2 files changed, 28 insertions(+), 7 deletions(-)

Comments

Richard Henderson May 21, 2021, 1:56 p.m. UTC | #1
On 5/19/21 9:29 AM, Mark Cave-Ayland wrote:
> The m68k trace mode is controlled by the top 2 bits in the SR register. Implement
> the m68k "any instruction" trace mode where bit T1=1 and bit T0=0 in which the CPU
> generates an EXCP_TRACE exception (vector 9 or offset 0x24) after executing each
> instruction.
> 
> This functionality is used by the NetBSD kernel debugger to allow single-stepping
> on m68k architectures.
> 
> Signed-off-by: Mark Cave-Ayland<mark.cave-ayland@ilande.co.uk>
> ---
>   target/m68k/cpu.h       |  8 ++++++++
>   target/m68k/translate.c | 27 ++++++++++++++++++++-------
>   2 files changed, 28 insertions(+), 7 deletions(-)

It wouldn't be difficult to handle 'trace on change of flow' as well, if you 
wanted.  But this is certainly good.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~
diff mbox series

Patch

diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 402c86c876..997d588911 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -230,6 +230,9 @@  typedef enum {
 #define SR_T_SHIFT 14
 #define SR_T  0xc000
 
+#define M68K_SR_TRACE(sr) ((sr & SR_T) >> SR_T_SHIFT)
+#define M68K_SR_TRACE_ANY_INS 0x2
+
 #define M68K_SSP    0
 #define M68K_USP    1
 #define M68K_ISP    2
@@ -590,6 +593,8 @@  typedef M68kCPU ArchCPU;
 #define TB_FLAGS_SFC_S          (1 << TB_FLAGS_SFC_S_BIT)
 #define TB_FLAGS_DFC_S_BIT      15
 #define TB_FLAGS_DFC_S          (1 << TB_FLAGS_DFC_S_BIT)
+#define TB_FLAGS_TRACE          16
+#define TB_FLAGS_TRACE_BIT      (1 << TB_FLAGS_TRACE)
 
 static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc,
                                         target_ulong *cs_base, uint32_t *flags)
@@ -602,6 +607,9 @@  static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc,
         *flags |= (env->sfc << (TB_FLAGS_SFC_S_BIT - 2)) & TB_FLAGS_SFC_S;
         *flags |= (env->dfc << (TB_FLAGS_DFC_S_BIT - 2)) & TB_FLAGS_DFC_S;
     }
+    if (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS) {
+        *flags |= TB_FLAGS_TRACE;
+    }
 }
 
 void dump_mmu(CPUM68KState *env);
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 10e8aba42e..f0c5bf9154 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -124,6 +124,7 @@  typedef struct DisasContext {
 #define MAX_TO_RELEASE 8
     int release_count;
     TCGv release[MAX_TO_RELEASE];
+    bool ss_active;
 } DisasContext;
 
 static void init_release_array(DisasContext *s)
@@ -197,12 +198,13 @@  static void do_writebacks(DisasContext *s)
 static bool is_singlestepping(DisasContext *s)
 {
     /*
-     * Return true if we are singlestepping either because of QEMU gdbstub
-     * singlestep. This does not include the command line '-singlestep' mode
-     * which is rather misnamed as it only means "one instruction per TB" and
-     * doesn't affect the code we generate.
+     * Return true if we are singlestepping either because of
+     * architectural singlestep or QEMU gdbstub singlestep. This does
+     * not include the command line '-singlestep' mode which is rather
+     * misnamed as it only means "one instruction per TB" and doesn't
+     * affect the code we generate.
      */
-    return s->base.singlestep_enabled;
+    return s->base.singlestep_enabled || s->ss_active;
 }
 
 /* is_jmp field values */
@@ -323,9 +325,14 @@  static void gen_singlestep_exception(DisasContext *s)
 {
     /*
      * Generate the right kind of exception for singlestep, which is
-     * EXCP_DEBUG for QEMU's gdb singlestepping.
+     * either the architectural singlestep or EXCP_DEBUG for QEMU's
+     * gdb singlestepping.
      */
-    gen_raise_exception(EXCP_DEBUG);
+    if (s->ss_active) {
+        gen_raise_exception(EXCP_TRACE);
+    } else {
+        gen_raise_exception(EXCP_DEBUG);
+    }
 }
 
 static inline void gen_addr_fault(DisasContext *s)
@@ -6194,6 +6201,12 @@  static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
     dc->done_mac = 0;
     dc->writeback_mask = 0;
     init_release_array(dc);
+
+    dc->ss_active = (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS);
+    /* If architectural single step active, limit to 1 */
+    if (is_singlestepping(dc)) {
+        dc->base.max_insns = 1;
+    }
 }
 
 static void m68k_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)