Merge zizzer.eecs.umich.edu:/bk/newmem
[gem5.git] / src / arch / sparc / tlb.cc
index 675287d1875af808c04d9f8abb446486323c9eb7..1a2ec6eac8ea50aab6a97f35749341ec8df05dbd 100644 (file)
@@ -45,7 +45,8 @@ namespace SparcISA
 {
 
 TLB::TLB(const std::string &name, int s)
-    : SimObject(name), size(s), usedEntries(0), cacheValid(false)
+    : SimObject(name), size(s), usedEntries(0), lastReplaced(0),
+      cacheValid(false)
 {
     // To make this work you'll have to change the hypervisor and OS
     if (size > 64)
@@ -53,13 +54,16 @@ TLB::TLB(const std::string &name, int s)
 
     tlb = new TlbEntry[size];
     memset(tlb, 0, sizeof(TlbEntry) * size);
+
+    for (int x = 0; x < size; x++)
+        freeList.push_back(&tlb[x]);
 }
 
 void
 TLB::clearUsedBits()
 {
     MapIter i;
-    for (i = lookupTable.begin(); i != lookupTable.end();) {
+    for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
         TlbEntry *t = i->second;
         if (!t->pte.locked()) {
             t->used = false;
@@ -77,32 +81,104 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real,
 
     MapIter i;
     TlbEntry *new_entry = NULL;
+//    TlbRange tr;
     int x;
 
     cacheValid = false;
+    va &= ~(PTE.size()-1);
+ /*   tr.va = va;
+    tr.size = PTE.size() - 1;
+    tr.contextId = context_id;
+    tr.partitionId = partition_id;
+    tr.real = real;
+*/
 
-    DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d\n",
-            va, PTE.paddr(), partition_id, context_id, (int)real);
+    DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
+            va, PTE.paddr(), partition_id, context_id, (int)real, entry);
+
+    // Demap any entry that conflicts
+    for (x = 0; x < size; x++) {
+        if (tlb[x].range.real == real &&
+            tlb[x].range.partitionId == partition_id &&
+            tlb[x].range.va < va + PTE.size() - 1 &&
+            tlb[x].range.va + tlb[x].range.size >= va &&
+            (real || tlb[x].range.contextId == context_id ))
+        {
+            if (tlb[x].valid) {
+                freeList.push_front(&tlb[x]);
+                DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x);
+
+                tlb[x].valid = false;
+                if (tlb[x].used) {
+                    tlb[x].used = false;
+                    usedEntries--;
+                }
+                lookupTable.erase(tlb[x].range);
+            }
+        }
+    }
+
+
+/*
+    i = lookupTable.find(tr);
+    if (i != lookupTable.end()) {
+        i->second->valid = false;
+        if (i->second->used) {
+            i->second->used = false;
+            usedEntries--;
+        }
+        freeList.push_front(i->second);
+        DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n",
+                i->second);
+        lookupTable.erase(i);
+    }
+*/
 
     if (entry != -1) {
         assert(entry < size && entry >= 0);
         new_entry = &tlb[entry];
     } else {
+        if (!freeList.empty()) {
+            new_entry = freeList.front();
+        } else {
+            x = lastReplaced;
+            do {
+                ++x;
+                if (x == size)
+                    x = 0;
+                if (x == lastReplaced)
+                    goto insertAllLocked;
+            } while (tlb[x].pte.locked());
+            lastReplaced = x;
+            new_entry = &tlb[x];
+        }
+        /*
         for (x = 0; x < size; x++) {
             if (!tlb[x].valid || !tlb[x].used)  {
                 new_entry = &tlb[x];
                 break;
             }
-        }
+        }*/
     }
 
+insertAllLocked:
     // Update the last ently if their all locked
-    if (!new_entry)
+    if (!new_entry) {
         new_entry = &tlb[size-1];
+    }
+
+    freeList.remove(new_entry);
+    if (new_entry->valid && new_entry->used)
+        usedEntries--;
+
+    lookupTable.erase(new_entry->range);
+
+
+    DPRINTF(TLB, "Using entry: %#X\n", new_entry);
 
     assert(PTE.valid());
     new_entry->range.va = va;
-    new_entry->range.size = PTE.size();
+    new_entry->range.size = PTE.size() - 1;
     new_entry->range.partitionId = partition_id;
     new_entry->range.contextId = context_id;
     new_entry->range.real = real;
@@ -112,19 +188,9 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real,
     usedEntries++;
 
 
-    // Demap any entry that conflicts
-    i = lookupTable.find(new_entry->range);
-    if (i != lookupTable.end()) {
-        i->second->valid = false;
-        if (i->second->used) {
-            i->second->used = false;
-            usedEntries--;
-        }
-        DPRINTF(TLB, "TLB: Found conflicting entry, deleting it\n");
-        lookupTable.erase(i);
-    }
 
-    lookupTable.insert(new_entry->range, new_entry);;
+    i = lookupTable.insert(new_entry->range, new_entry);
+    assert(i != lookupTable.end());
 
     // If all entries have there used bit set, clear it on them all, but the
     // one we just inserted
@@ -148,7 +214,7 @@ TLB::lookup(Addr va, int partition_id, bool real, int context_id)
             va, partition_id, context_id, real);
     // Assemble full address structure
     tr.va = va;
-    tr.size = va + MachineBytes;
+    tr.size = MachineBytes;
     tr.contextId = context_id;
     tr.partitionId = partition_id;
     tr.real = real;
@@ -180,6 +246,7 @@ TLB::lookup(Addr va, int partition_id, bool real, int context_id)
 void
 TLB::dumpAll()
 {
+    MapIter i;
     for (int x = 0; x < size; x++) {
         if (tlb[x].valid) {
            DPRINTFN("%4d:  %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
@@ -196,11 +263,14 @@ TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
     TlbRange tr;
     MapIter i;
 
+    DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
+            va, partition_id, context_id, real);
+
     cacheValid = false;
 
     // Assemble full address structure
     tr.va = va;
-    tr.size = va + MachineBytes;
+    tr.size = MachineBytes;
     tr.contextId = context_id;
     tr.partitionId = partition_id;
     tr.real = real;
@@ -208,11 +278,14 @@ TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
     // Demap any entry that conflicts
     i = lookupTable.find(tr);
     if (i != lookupTable.end()) {
+        DPRINTF(IPR, "TLB: Demapped page\n");
         i->second->valid = false;
         if (i->second->used) {
             i->second->used = false;
             usedEntries--;
         }
+        freeList.push_front(i->second);
+        DPRINTF(TLB, "Freeing TLB entry : %#X\n", i->second);
         lookupTable.erase(i);
     }
 }
@@ -221,10 +294,16 @@ void
 TLB::demapContext(int partition_id, int context_id)
 {
     int x;
+    DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
+            partition_id, context_id);
     cacheValid = false;
     for (x = 0; x < size; x++) {
         if (tlb[x].range.contextId == context_id &&
             tlb[x].range.partitionId == partition_id) {
+            if (tlb[x].valid == true) {
+                freeList.push_front(&tlb[x]);
+                DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
+            }
             tlb[x].valid = false;
             if (tlb[x].used) {
                 tlb[x].used = false;
@@ -239,9 +318,14 @@ void
 TLB::demapAll(int partition_id)
 {
     int x;
+    DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
     cacheValid = false;
     for (x = 0; x < size; x++) {
         if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
+            if (tlb[x].valid == true){
+                freeList.push_front(&tlb[x]);
+                DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
+            }
             tlb[x].valid = false;
             if (tlb[x].used) {
                 tlb[x].used = false;
@@ -258,25 +342,39 @@ TLB::invalidateAll()
     int x;
     cacheValid = false;
 
+    freeList.clear();
+    lookupTable.clear();
     for (x = 0; x < size; x++) {
+        if (tlb[x].valid == true)
+            freeList.push_back(&tlb[x]);
         tlb[x].valid = false;
+        tlb[x].used = false;
     }
     usedEntries = 0;
 }
 
 uint64_t
 TLB::TteRead(int entry) {
+    if (entry >= size)
+        panic("entry: %d\n", entry);
+
     assert(entry < size);
-    return tlb[entry].pte();
+    if (tlb[entry].valid)
+        return tlb[entry].pte();
+    else
+        return (uint64_t)-1ll;
 }
 
 uint64_t
 TLB::TagRead(int entry) {
     assert(entry < size);
     uint64_t tag;
+    if (!tlb[entry].valid)
+        return (uint64_t)-1ll;
 
-    tag = tlb[entry].range.contextId | tlb[entry].range.va |
-          (uint64_t)tlb[entry].range.partitionId << 61;
+    tag = tlb[entry].range.contextId;
+    tag |= tlb[entry].range.va;
+    tag |= (uint64_t)tlb[entry].range.partitionId << 61;
     tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
     tag |= (uint64_t)~tlb[entry].pte._size() << 56;
     return tag;
@@ -317,6 +415,9 @@ TLB::writeSfsr(ThreadContext *tc, int reg,  bool write, ContextType ct,
 void
 TLB::writeTagAccess(ThreadContext *tc, int reg, Addr va, int context)
 {
+    DPRINTF(TLB, "TLB: Writing Tag Access: va: %#X ctx: %#X value: %#X\n",
+            va, context, mbits(va, 63,13) | mbits(context,12,0));
+
     tc->setMiscRegWithEffect(reg, mbits(va, 63,13) | mbits(context,12,0));
 }
 
@@ -439,8 +540,7 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
     }
 
     if (e == NULL || !e->valid) {
-        tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
-                vaddr & ~BytesInPageMask | context);
+        writeTagAccess(tc, vaddr, context);
         if (real)
             return new InstructionRealTranslationMiss;
         else
@@ -492,13 +592,13 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
     // Be fast if we can!
     if (cacheValid &&  cacheState == tlbdata) {
         if (cacheEntry[0] && cacheAsi[0] == asi && cacheEntry[0]->range.va < vaddr + size &&
-            cacheEntry[0]->range.va + cacheEntry[0]->range.size >= vaddr) {
+            cacheEntry[0]->range.va + cacheEntry[0]->range.size > vaddr) {
                 req->setPaddr(cacheEntry[0]->pte.paddr() & ~(cacheEntry[0]->pte.size()-1) |
                               vaddr & cacheEntry[0]->pte.size()-1 );
                 return NoFault;
         }
         if (cacheEntry[1] && cacheAsi[1] == asi && cacheEntry[1]->range.va < vaddr + size &&
-            cacheEntry[1]->range.va + cacheEntry[1]->range.size >= vaddr) {
+            cacheEntry[1]->range.va + cacheEntry[1]->range.size > vaddr) {
                 req->setPaddr(cacheEntry[1]->pte.paddr() & ~(cacheEntry[1]->pte.size()-1) |
                               vaddr & cacheEntry[1]->pte.size()-1 );
                 return NoFault;
@@ -513,7 +613,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
     int part_id = bits(tlbdata,15,8);
     int tl = bits(tlbdata,18,16);
     int pri_context = bits(tlbdata,47,32);
-    int sec_context = bits(tlbdata,47,32);
+    int sec_context = bits(tlbdata,63,48);
 
     bool real = false;
     ContextType ct = Primary;
@@ -534,49 +634,42 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
             ct = Primary;
             context = pri_context;
         }
-    } else if (!hpriv && !red) {
-        if (tl > 0 || AsiIsNucleus(asi)) {
-            ct = Nucleus;
-            context = 0;
-        } else if (AsiIsSecondary(asi)) {
-            ct = Secondary;
-            context = sec_context;
-        } else {
-            context = pri_context;
-            ct = Primary; //???
-        }
-
+    } else {
         // We need to check for priv level/asi priv
-        if (!priv && !AsiIsUnPriv(asi)) {
+        if (!priv && !hpriv && !AsiIsUnPriv(asi)) {
             // It appears that context should be Nucleus in these cases?
             writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
             return new PrivilegedAction;
         }
-        if (priv && AsiIsHPriv(asi)) {
+
+        if (!hpriv && AsiIsHPriv(asi)) {
             writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
             return new DataAccessException;
         }
 
-    } else if (hpriv) {
-        if (asi == ASI_P) {
+        if (AsiIsPrimary(asi)) {
+            context = pri_context;
+            ct = Primary;
+        } else if (AsiIsSecondary(asi)) {
+            context = sec_context;
+            ct = Secondary;
+        } else if (AsiIsNucleus(asi)) {
+            ct = Nucleus;
+            context = 0;
+        } else {  // ????
             ct = Primary;
             context = pri_context;
-            goto continueDtbFlow;
         }
     }
 
-    if (!implicit) {
+    if (!implicit && asi != ASI_P && asi != ASI_S) {
         if (AsiIsLittle(asi))
             panic("Little Endian ASIs not supported\n");
         if (AsiIsBlock(asi))
             panic("Block ASIs not supported\n");
         if (AsiIsNoFault(asi))
             panic("No Fault ASIs not supported\n");
-        if (write && asi == ASI_LDTX_P)
-            // block init store (like write hint64)
-            goto continueDtbFlow;
-        if (AsiIsTwin(asi))
-            panic("Twin ASIs not supported\n");
+
         if (AsiIsPartialStore(asi))
             panic("Partial Store ASIs not supported\n");
         if (AsiIsInterrupt(asi))
@@ -591,11 +684,11 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
         if (AsiIsSparcError(asi))
             goto handleSparcErrorRegAccess;
 
-        if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
+        if (!AsiIsReal(asi) && !AsiIsNucleus(asi) && !AsiIsAsIfUser(asi) &&
+                !AsiIsTwin(asi))
             panic("Accessing ASI %#X. Should we?\n", asi);
     }
 
-continueDtbFlow:
     // If the asi is unaligned trap
     if (vaddr & size-1) {
         writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
@@ -611,7 +704,7 @@ continueDtbFlow:
     }
 
 
-    if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) {
+    if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) {
         real = true;
         context = 0;
     };
@@ -624,8 +717,7 @@ continueDtbFlow:
     e = lookup(vaddr, part_id, real, context);
 
     if (e == NULL || !e->valid) {
-        tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
-                vaddr & ~BytesInPageMask | context);
+        writeTagAccess(tc, vaddr, context);
         DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
         if (real)
             return new DataRealTranslationMiss;
@@ -655,8 +747,12 @@ continueDtbFlow:
     }
 
     // cache translation date for next translation
-    cacheValid = true;
     cacheState = tlbdata;
+    if (!cacheValid) {
+        cacheEntry[1] = NULL;
+        cacheEntry[0] = NULL;
+    }
+
     if (cacheEntry[0] != e && cacheEntry[1] != e) {
         cacheEntry[1] = cacheEntry[0];
         cacheEntry[0] = e;
@@ -665,7 +761,7 @@ continueDtbFlow:
         if (implicit)
             cacheAsi[0] = (ASI)0;
     }
-
+    cacheValid = true;
     req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
                   vaddr & e->pte.size()-1);
     DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
@@ -684,7 +780,7 @@ handleQueueRegAccess:
         writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
         return new PrivilegedAction;
     }
-    if (priv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
+    if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
         writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
         return new DataAccessException;
     }
@@ -793,7 +889,7 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
         break;
       case ASI_SPARC_ERROR_STATUS_REG:
         warn("returning 0 for  SPARC ERROR regsiter read\n");
-        pkt->set(0);
+        pkt->set((uint64_t)0);
         break;
       case ASI_HYP_SCRATCHPAD:
       case ASI_SCRATCHPAD:
@@ -805,6 +901,9 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
             temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
             pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
             break;
+          case 0x18:
+            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_SFSR));
+            break;
           case 0x30:
             pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS));
             break;
@@ -818,6 +917,12 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
             temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
             pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
             break;
+          case 0x18:
+            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_SFSR));
+            break;
+          case 0x20:
+            pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR));
+            break;
           case 0x30:
             pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS));
             break;
@@ -854,10 +959,40 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
         data = mbits(tsbtemp,63,13);
         if (bits(tsbtemp,12,12))
             data |= ULL(1) << (13+bits(tsbtemp,3,0));
+        data |= temp >> (9 + bits(cnftemp,10,8) * 3) &
+            mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
+        pkt->set(data);
+        break;
+      case ASI_IMMU_TSB_PS0_PTR_REG:
+        temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
+        if (bits(temp,12,0) == 0) {
+            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0);
+            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG);
+        } else {
+            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0);
+            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG);
+        }
+        data = mbits(tsbtemp,63,13);
         data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
             mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
         pkt->set(data);
         break;
+      case ASI_IMMU_TSB_PS1_PTR_REG:
+        temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
+        if (bits(temp,12,0) == 0) {
+            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1);
+            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG);
+        } else {
+            tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1);
+            cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG);
+        }
+        data = mbits(tsbtemp,63,13);
+        if (bits(tsbtemp,12,12))
+            data |= ULL(1) << (13+bits(tsbtemp,3,0));
+        data |= temp >> (9 + bits(cnftemp,10,8) * 3) &
+            mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
+        pkt->set(data);
+        break;
 
       default:
 doMmuReadError:
@@ -881,6 +1016,9 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
     int part_insert;
     int entry_insert = -1;
     bool real_insert;
+    bool ignore;
+    int part_id;
+    int ctx_id;
     PageTableEntry pte;
 
     DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
@@ -966,7 +1104,11 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
         break;
       case ASI_IMMU:
         switch (va) {
+          case 0x18:
+            tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_SFSR, data);
+            break;
           case 0x30:
+            sext<59>(bits(data, 59,0));
             tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data);
             break;
           default:
@@ -1000,9 +1142,48 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
                 PageTableEntry::sun4u);
         insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
         break;
+      case ASI_IMMU_DEMAP:
+        ignore = false;
+        ctx_id = -1;
+        part_id =  tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
+        switch (bits(va,5,4)) {
+          case 0:
+            ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
+            break;
+          case 1:
+            ignore = true;
+            break;
+          case 3:
+            ctx_id = 0;
+            break;
+          default:
+            ignore = true;
+        }
+
+        switch(bits(va,7,6)) {
+          case 0: // demap page
+            if (!ignore)
+                tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
+                        bits(va,9,9), ctx_id);
+            break;
+          case 1: //demap context
+            if (!ignore)
+                tc->getITBPtr()->demapContext(part_id, ctx_id);
+            break;
+          case 2:
+            tc->getITBPtr()->demapAll(part_id);
+            break;
+          default:
+            panic("Invalid type for IMMU demap\n");
+        }
+        break;
       case ASI_DMMU:
         switch (va) {
+          case 0x18:
+            tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFSR, data);
+            break;
           case 0x30:
+            sext<59>(bits(data, 59,0));
             tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data);
             break;
           case 0x80:
@@ -1012,6 +1193,40 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
             goto doMmuWriteError;
         }
         break;
+      case ASI_DMMU_DEMAP:
+        ignore = false;
+        ctx_id = -1;
+        part_id =  tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
+        switch (bits(va,5,4)) {
+          case 0:
+            ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
+            break;
+          case 1:
+            ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT);
+            break;
+          case 3:
+            ctx_id = 0;
+            break;
+          default:
+            ignore = true;
+        }
+
+        switch(bits(va,7,6)) {
+          case 0: // demap page
+            if (!ignore)
+                demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
+            break;
+          case 1: //demap context
+            if (!ignore)
+                demapContext(part_id, ctx_id);
+            break;
+          case 2:
+            demapAll(part_id);
+            break;
+          default:
+            panic("Invalid type for IMMU demap\n");
+        }
+        break;
       default:
 doMmuWriteError:
         panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",