diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index b26a49e0fe..4cb75f558e 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -76,6 +76,14 @@
 #define EXCP_RTE            0x100
 #define EXCP_HALT_INSN      0x101
 
+#define M68K_DTTR0   0
+#define M68K_DTTR1   1
+#define M68K_ITTR0   2
+#define M68K_ITTR1   3
+
+#define M68K_MAX_TTR 2
+#define TTR(type, index) ttr[((type & ACCESS_CODE) == ACCESS_CODE) * 2 + index]
+
 #define NB_MMU_MODES 2
 #define TARGET_INSN_START_EXTRA_WORDS 1
 
@@ -122,6 +130,7 @@ typedef struct CPUM68KState {
         uint32_t urp;
         uint32_t srp;
         bool fault;
+        uint32_t ttr[4];
     } mmu;
 
     /* Control registers.  */
@@ -316,6 +325,15 @@ typedef enum {
 #define M68K_PDT_INDIRECT(entry)    ((entry & 3) == 2)
 #define M68K_INDIRECT_POINTER(addr) (addr & ~3)
 
+/* bits for 68040 MMU Transparent Translation Registers */
+#define M68K_TTR_ADDR_BASE 0xff000000
+#define M68K_TTR_ADDR_MASK 0x00ff0000
+#define M68K_TTR_ADDR_MASK_SHIFT    8
+#define M68K_TTR_ENABLED   0x00008000
+#define M68K_TTR_SFIELD    0x00006000
+#define M68K_TTR_SFIELD_USER   0x0000
+#define M68K_TTR_SFIELD_SUPER  0x2000
+
 /* m68k Control Registers */
 
 /* ColdFire */
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 13c6bb3d25..f1d50e54b1 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -230,6 +230,19 @@ void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
     case M68K_CR_ISP:
         env->sp[M68K_ISP] = val;
         return;
+    /* MC68040/MC68LC040 */
+    case M68K_CR_ITT0:
+        env->mmu.ttr[M68K_ITTR0] = val;
+        return;
+    case M68K_CR_ITT1:
+         env->mmu.ttr[M68K_ITTR1] = val;
+        return;
+    case M68K_CR_DTT0:
+        env->mmu.ttr[M68K_DTTR0] = val;
+        return;
+    case M68K_CR_DTT1:
+        env->mmu.ttr[M68K_DTTR1] = val;
+        return;
     }
     cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
               reg, val);
@@ -260,6 +273,14 @@ uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
     /* MC68040/MC68LC040 */
     case M68K_CR_URP:
         return env->mmu.urp;
+    case M68K_CR_ITT0:
+        return env->mmu.ttr[M68K_ITTR0];
+    case M68K_CR_ITT1:
+        return env->mmu.ttr[M68K_ITTR1];
+    case M68K_CR_DTT0:
+        return env->mmu.ttr[M68K_DTTR0];
+    case M68K_CR_DTT1:
+        return env->mmu.ttr[M68K_DTTR1];
     }
     cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n",
               reg);
@@ -338,6 +359,53 @@ int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
 
 /* MMU: 68040 only */
 
+static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
+                     int access_type)
+{
+    uint32_t base, mask;
+
+    /* check if transparent translation is enabled */
+    if ((ttr & M68K_TTR_ENABLED) == 0) {
+        return 0;
+    }
+
+    /* check mode access */
+    switch (ttr & M68K_TTR_SFIELD) {
+    case M68K_TTR_SFIELD_USER:
+        /* match only if user */
+        if ((access_type & ACCESS_SUPER) != 0) {
+            return 0;
+        }
+        break;
+    case M68K_TTR_SFIELD_SUPER:
+        /* match only if supervisor */
+        if ((access_type & ACCESS_SUPER) == 0) {
+            return 0;
+        }
+        break;
+    default:
+        /* all other values disable mode matching (FC2) */
+        break;
+    }
+
+    /* check address matching */
+
+    base = ttr & M68K_TTR_ADDR_BASE;
+    mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
+    mask <<= M68K_TTR_ADDR_MASK_SHIFT;
+
+    if ((addr & mask) != (base & mask)) {
+        return 0;
+    }
+
+    *prot = PAGE_READ | PAGE_EXEC;
+    if ((ttr & M68K_DESC_WRITEPROT) == 0) {
+        *prot |= PAGE_WRITE;
+    }
+
+    return 1;
+}
+
 static int get_physical_address(CPUM68KState *env, hwaddr *physical,
                                 int *prot, target_ulong address,
                                 int access_type, target_ulong *page_size)
@@ -350,6 +418,17 @@ static int get_physical_address(CPUM68KState *env, hwaddr *physical,
     target_ulong page_mask;
     bool debug = access_type & ACCESS_DEBUG;
     int page_bits;
+    int i;
+
+    /* Transparent Translation (physical = logical) */
+    for (i = 0; i < M68K_MAX_TTR; i++) {
+        if (check_TTR(env->mmu.TTR(access_type, i),
+                      prot, address, access_type)) {
+            *physical = address;
+            *page_size = TARGET_PAGE_SIZE;
+            return 0;
+        }
+    }
 
     /* Page Table Root Pointer */
     *prot = PAGE_READ | PAGE_WRITE;
diff --git a/target/m68k/monitor.c b/target/m68k/monitor.c
index 2b83e3bc0d..a20af6b09c 100644
--- a/target/m68k/monitor.c
+++ b/target/m68k/monitor.c
@@ -33,6 +33,10 @@ static const MonitorDef monitor_defs[] = {
     { "isp", offsetof(CPUM68KState, sp[2]) },
     { "urp", offsetof(CPUM68KState, mmu.urp) },
     { "srp", offsetof(CPUM68KState, mmu.srp) },
+    { "dttr0", offsetof(CPUM68KState, mmu.ttr[M68K_DTTR0]) },
+    { "dttr1", offsetof(CPUM68KState, mmu.ttr[M68K_DTTR1]) },
+    { "ittr0", offsetof(CPUM68KState, mmu.ttr[M68K_ITTR0]) },
+    { "ittr1", offsetof(CPUM68KState, mmu.ttr[M68K_ITTR1]) },
     { NULL },
 };
 
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 5acee66208..af70825480 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5983,6 +5983,9 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
     cpu_fprintf(f, "VBR = 0x%08x\n", env->vbr);
     cpu_fprintf(f, "SSW %08x TCR %08x URP %08x SRP %08x\n",
                 env->mmu.ssw, env->mmu.tcr, env->mmu.urp, env->mmu.srp);
+    cpu_fprintf(f, "DTTR0/1: %08x/%08x ITTR0/1: %08x/%08x\n",
+                env->mmu.ttr[M68K_DTTR0], env->mmu.ttr[M68K_DTTR1],
+                env->mmu.ttr[M68K_ITTR0], env->mmu.ttr[M68K_ITTR1]);
 #endif
 }
 
