diff --git a/sim/common/sim-trace.c b/sim/common/sim-trace.c
index e69c62d..66ff4ac 100644
--- a/sim/common/sim-trace.c
+++ b/sim/common/sim-trace.c
@@ -25,6 +25,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "bfd.h"
 #include "libiberty.h"
 
+#include "dis-asm.h"
+
 #include "sim-assert.h"
 
 #ifdef HAVE_STRING_H
@@ -61,6 +63,7 @@ static DECLARE_OPTION_HANDLER (trace_option_handler);
 
 enum {
   OPTION_TRACE_INSN	= OPTION_START,
+  OPTION_TRACE_DISASM,
   OPTION_TRACE_DECODE,
   OPTION_TRACE_EXTRACT,
   OPTION_TRACE_LINENUM,
@@ -90,6 +93,9 @@ static const OPTION trace_options[] =
   { {"trace-insn", optional_argument, NULL, OPTION_TRACE_INSN},
       '\0', "on|off", "Perform instruction tracing",
       trace_option_handler, NULL },
+  { {"trace-disasm", optional_argument, NULL, OPTION_TRACE_DISASM},
+      '\0', "on|off", "Disassemble instructions (slower, but more accurate)",
+      trace_option_handler, NULL },
   { {"trace-decode", optional_argument, NULL, OPTION_TRACE_DECODE},
       '\0', "on|off", "Trace instruction decoding",
       trace_option_handler, NULL },
@@ -249,6 +255,13 @@ trace_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
 	sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-insn' ignored\n");
       break;
 
+    case OPTION_TRACE_DISASM :
+      if (WITH_TRACE_DISASM_P)
+	return set_trace_option (sd, "-disasm", TRACE_DISASM_IDX, arg);
+      else
+	sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-disasm' ignored\n");
+      break;
+
     case OPTION_TRACE_DECODE :
       if (WITH_TRACE_DECODE_P)
 	return set_trace_option (sd, "-decode", TRACE_DECODE_IDX, arg);
@@ -616,6 +629,7 @@ trace_idx_to_str (int trace_idx)
     {
     case TRACE_ALU_IDX:      return "alu:     ";
     case TRACE_INSN_IDX:     return "insn:    ";
+    case TRACE_DISASM_IDX:   return "disasm:  ";
     case TRACE_DECODE_IDX:   return "decode:  ";
     case TRACE_EXTRACT_IDX:  return "extract: ";
     case TRACE_MEMORY_IDX:   return "memory:  ";
@@ -837,6 +851,54 @@ trace_generic (SIM_DESC sd,
   trace_printf (sd, cpu, "\n");
 }
 
+static int
+dis_read (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
+	  struct disassemble_info *dinfo)
+{
+  SIM_CPU *cpu = dinfo->application_data;
+  sim_core_read_buffer (CPU_STATE (cpu), cpu, NULL_CIA, myaddr, memaddr, length);
+  return 0;
+}
+
+static int
+dis_printf (SIM_CPU *cpu, const char *fmt, ...)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  va_list ap;
+  va_start (ap, fmt);
+  trace_vprintf (sd, cpu, fmt, ap);
+  va_end (ap);
+  return 0;
+}
+
+void
+trace_disasm (SIM_DESC sd, sim_cpu *cpu, address_word addr)
+{
+  struct bfd *bfd = STATE_PROG_BFD (sd);
+  TRACE_DATA *trace_data = CPU_TRACE_DATA (cpu);
+  disassemble_info *info = &trace_data->dis_info;
+
+  /* See if we need to set up the disassembly func.  */
+  if (trace_data->dis_bfd != bfd)
+    {
+      trace_data->dis_bfd = bfd;
+      trace_data->disassembler = disassembler (trace_data->dis_bfd);
+      INIT_DISASSEMBLE_INFO (*info, cpu, dis_printf);
+      info->read_memory_func = dis_read;
+      info->arch = bfd_get_arch (bfd);
+      info->mach = bfd_get_mach (bfd);
+      disassemble_init_for_target (info);
+    }
+
+  info->application_data = cpu;
+
+  trace_printf (sd, cpu, "%s %s",
+		trace_idx_to_str (TRACE_DISASM_IDX),
+		TRACE_PREFIX (trace_data));
+  trace_data->disassembler (addr, info);
+  trace_printf (sd, cpu, "\n");
+}
+
 void
 trace_input0 (SIM_DESC sd,
 	      sim_cpu *cpu,
diff --git a/sim/common/sim-trace.h b/sim/common/sim-trace.h
index 28fc351..87e0478 100644
--- a/sim/common/sim-trace.h
+++ b/sim/common/sim-trace.h
@@ -22,12 +22,20 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifndef SIM_TRACE_H
 #define SIM_TRACE_H
 
+#include "dis-asm.h"
+
 /* Standard traceable entities.  */
 
 enum {
-  /* Trace insn execution.  */
+  /* Trace insn execution.  The port itself is responsible for displaying what
+     it thinks it is decoding.  */
   TRACE_INSN_IDX = 1,
 
+  /* Disassemble code addresses.  Like insn tracing, but relies on the opcode
+     framework for displaying code.  Can be slower, more accurate as to what
+     the binary code actually is, but not how the sim is decoding it.  */
+  TRACE_DISASM_IDX,
+
   /* Trace insn decoding.
      ??? This is more of a simulator debugging operation and might best be
      moved to --debug-decode.  */
@@ -97,6 +105,7 @@ enum {
    The case choice here is on purpose.  The lowercase parts are args to
    --with-trace.  */
 #define TRACE_insn     (1 << TRACE_INSN_IDX)
+#define TRACE_disasm   (1 << TRACE_DISASM_IDX)
 #define TRACE_decode   (1 << TRACE_DECODE_IDX)
 #define TRACE_extract  (1 << TRACE_EXTRACT_IDX)
 #define TRACE_linenum  (1 << TRACE_LINENUM_IDX)
@@ -118,6 +127,7 @@ enum {
 /* Preprocessor macros to simplify tests of WITH_TRACE.  */
 #define WITH_TRACE_ANY_P	(WITH_TRACE)
 #define WITH_TRACE_INSN_P	WITH_TRACE_P (TRACE_INSN_IDX)
+#define WITH_TRACE_DISASM_P	WITH_TRACE_P (TRACE_DISASM_IDX)
 #define WITH_TRACE_DECODE_P	WITH_TRACE_P (TRACE_DECODE_IDX)
 #define WITH_TRACE_EXTRACT_P	WITH_TRACE_P (TRACE_EXTRACT_IDX)
 #define WITH_TRACE_LINENUM_P	WITH_TRACE_P (TRACE_LINENUM_IDX)
@@ -190,6 +200,19 @@ typedef struct _trace_data {
      ??? Not all cpu's support this.  */
   ADDR_RANGE range;
 #define TRACE_RANGE(t) (& (t)->range)
+
+  /* The bfd used to disassemble code.  Should compare against STATE_PROG_BFD
+     before using the disassembler helper.
+     Meant for use by the internal trace module only.  */
+  struct bfd *dis_bfd;
+
+  /* The function used to actually disassemble code.
+     Meant for use by the internal trace module only.  */
+  disassembler_ftype disassembler;
+
+  /* State used with the disassemble function.
+     Meant for use by the internal trace module only.  */
+  disassemble_info dis_info;
 } TRACE_DATA;
 
 /* System tracing support.  */
@@ -204,6 +227,7 @@ typedef struct _trace_data {
 /* Non-zero if --trace-<xxxx> was specified for SD.  */
 #define STRACE_ANY_P(sd)	(WITH_TRACE_ANY_P && (STATE_TRACE_DATA (sd)->trace_any_p))
 #define STRACE_INSN_P(sd)	STRACE_P (sd, TRACE_INSN_IDX)
+#define STRACE_DISASM_P(sd)	STRACE_P (sd, TRACE_DISASM_IDX)
 #define STRACE_DECODE_P(sd)	STRACE_P (sd, TRACE_DECODE_IDX)
 #define STRACE_EXTRACT_P(sd)	STRACE_P (sd, TRACE_EXTRACT_IDX)
 #define STRACE_LINENUM_P(sd)	STRACE_P (sd, TRACE_LINENUM_IDX)
@@ -226,6 +250,7 @@ typedef struct _trace_data {
       trace_generic (sd, NULL, idx, fmt, ## args); \
   } while (0)
 #define STRACE_INSN(sd, fmt, args...)		STRACE (sd, TRACE_INSN_IDX, fmt, ## args)
+#define STRACE_DISASM(sd, fmt, args...)		STRACE (sd, TRACE_DISASM_IDX, fmt, ## args)
 #define STRACE_DECODE(sd, fmt, args...)		STRACE (sd, TRACE_DECODE_IDX, fmt, ## args)
 #define STRACE_EXTRACT(sd, fmt, args...)	STRACE (sd, TRACE_EXTRACT_IDX, fmt, ## args)
 #define STRACE_LINENUM(sd, fmt, args...)	STRACE (sd, TRACE_LINENUM_IDX, fmt, ## args)
@@ -252,6 +277,7 @@ typedef struct _trace_data {
 /* Non-zero if --trace-<xxxx> was specified for CPU.  */
 #define TRACE_ANY_P(cpu)	(WITH_TRACE_ANY_P && (CPU_TRACE_DATA (cpu)->trace_any_p))
 #define TRACE_INSN_P(cpu)	TRACE_P (cpu, TRACE_INSN_IDX)
+#define TRACE_DISASM_P(cpu)	TRACE_P (cpu, TRACE_DISASM_IDX)
 #define TRACE_DECODE_P(cpu)	TRACE_P (cpu, TRACE_DECODE_IDX)
 #define TRACE_EXTRACT_P(cpu)	TRACE_P (cpu, TRACE_EXTRACT_IDX)
 #define TRACE_LINENUM_P(cpu)	TRACE_P (cpu, TRACE_LINENUM_IDX)
@@ -266,6 +292,7 @@ typedef struct _trace_data {
 #define TRACE_SYSCALL_P(cpu)	TRACE_P (cpu, TRACE_SYSCALL_IDX)
 #define TRACE_REGISTER_P(cpu)	TRACE_P (cpu, TRACE_REGISTER_IDX)
 #define TRACE_DEBUG_P(cpu)	TRACE_P (cpu, TRACE_DEBUG_IDX)
+#define TRACE_DISASM_P(cpu)	TRACE_P (cpu, TRACE_DISASM_IDX)
 
 /* Helper functions for printing messages.  */
 #define TRACE(cpu, idx, fmt, args...) \
@@ -288,6 +315,11 @@ typedef struct _trace_data {
 #define TRACE_SYSCALL(cpu, fmt, args...)	TRACE (cpu, TRACE_SYSCALL_IDX, fmt, ## args)
 #define TRACE_REGISTER(cpu, fmt, args...)	TRACE (cpu, TRACE_REGISTER_IDX, fmt, ## args)
 #define TRACE_DEBUG(cpu, fmt, args...)		TRACE (cpu, TRACE_DEBUG_IDX, fmt, ## args)
+#define TRACE_DISASM(cpu, addr) \
+  do { \
+    if (TRACE_DISASM_P (cpu)) \
+      trace_disasm (CPU_STATE (cpu), cpu, addr); \
+  } while (0)
 
 /* Tracing functions.  */
 
@@ -313,6 +345,12 @@ extern void trace_generic (SIM_DESC sd,
 			   ...)
      __attribute__((format (printf, 4, 5)));
 
+/* Disassemble the specified address.  */
+
+extern void trace_disasm (SIM_DESC sd,
+			  sim_cpu *cpu,
+			  address_word addr);
+
 typedef enum {
   trace_fmt_invalid,
   trace_fmt_word,
