Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 98 additions & 62 deletions cpu/ppc/ppcmmu.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,58 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio, bool
return MapDmaResult{RT_NONE, false, nullptr, nullptr, 0};
}

constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

// PAT context changes are frequent, so implicitly invalidate PAT-derived
// entries via a generation counter (instead of walking the TLB array and
// clearing every time).
static uint32_t gTLBPatGeneration = 0;

typedef struct TLBEntry {
uint32_t tag; // use is_invalid() or matches_tag() for validity checks
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t pat_generation;

bool is_invalid() const
{
return tag == TLB_INVALID_TAG ||
((flags & TLBFlags::TLBE_FROM_PAT) &&
pat_generation != gTLBPatGeneration);
}

bool matches_tag(uint32_t tag_in) const
{
return tag == tag_in &&
(!(flags & TLBFlags::TLBE_FROM_PAT) ||
pat_generation == gTLBPatGeneration);
}
} TLBEntry;

// primary ITLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> itlb1_mode1;
static std::array<TLBEntry, TLB_SIZE> itlb1_mode2;
Expand DownExpand Up@@ -555,28 +607,28 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
}

// select the target from invalid blocks first
if (tlb_entry[0].tag == TLB_INVALID_TAG) {
if (tlb_entry[0].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return tlb_entry;
} else if (tlb_entry[1].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[1].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return &tlb_entry[1];
} else if (tlb_entry[2].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[2].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
return &tlb_entry[2];
} else if (tlb_entry[3].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[3].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -666,6 +718,7 @@ static TLBEntry* itlb2_refill(uint32_t guest_va)
tlb_entry->host_va_offs_r = (int64_t)rgn_desc->mem_ptr - guest_va +
(phys_addr - rgn_desc->start);
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
} else {
ABORT_F("Instruction fetch from unmapped memory at 0x%08X!\n", phys_addr);
}
Expand DownExpand Up@@ -749,6 +802,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write, bool is_dbg = fal
}
}
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
return tlb_entry;
} else {
if (!is_dbg) {
Expand DownExpand Up@@ -777,27 +831,27 @@ static inline TLBEntry* lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
tlb_entry = &pCurDTLB2[((guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask) * TLB2_WAYS];
}

if (tlb_entry->tag == tag) {
if (tlb_entry[0].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
} else if (tlb_entry[1].tag == tag) {
} else if (tlb_entry[1].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
tlb_entry = &tlb_entry[1];
} else if (tlb_entry[2].tag == tag) {
} else if (tlb_entry[2].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
tlb_entry = &tlb_entry[2];
} else if (tlb_entry[3].tag == tag) {
} else if (tlb_entry[3].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -829,7 +883,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)

// look up guest virtual address in the primary ITLB
tlb1_entry = &pCurITLB1[(vaddr >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary ITLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary ITLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_itlb_hits++;
#endif
Expand All@@ -855,6 +909,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r;
tlb1_entry->phys_tag = tlb2_entry->phys_tag;
tlb1_entry->pat_generation = tlb2_entry->pat_generation;
host_va = (uint8_t *)(tlb1_entry->host_va_offs_r + vaddr);
}

Expand DownExpand Up@@ -940,10 +995,9 @@ void tlb_flush_entries(TLBFlags type)
}
}

bool gTLBFlushIBatEntries = false;
bool gTLBFlushDBatEntries = false;
bool gTLBFlushIPatEntries = false;
bool gTLBFlushDPatEntries = false;
static bool gTLBFlushIBatEntries = false;
static bool gTLBFlushDBatEntries = false;
static bool gTLBInvalidatePatEntries = false;

template <const TLBType tlb_type>
void tlb_flush_bat_entries()
Expand All@@ -961,38 +1015,18 @@ void tlb_flush_bat_entries()
}
}

template <const TLBType tlb_type>
void tlb_flush_pat_entries()
static void tlb_invalidate_pat_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIPatEntries)
return;
if (!gTLBInvalidatePatEntries)
return;

gTLBPatGeneration++;
if (gTLBPatGeneration == 0) { // Do a full flush when the counter wraps around
tlb_flush_entries<TLBType::ITLB>(TLBE_FROM_PAT);
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>(TLBE_FROM_PAT);
gTLBFlushDPatEntries = false;
}
}

template <const TLBType tlb_type>
void tlb_flush_all_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIBatEntries && !gTLBFlushIPatEntries)
return;
tlb_flush_entries<TLBType::ITLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushIBatEntries = false;
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDBatEntries && !gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushDBatEntries = false;
gTLBFlushDPatEntries = false;
}
gTLBInvalidatePatEntries = false;
}

static void mpc601_bat_update(uint32_t bat_reg)
Expand DownExpand Up@@ -1026,14 +1060,15 @@ static void mpc601_bat_update(uint32_t bat_reg)
}

// MPC601 has unified BATs so we're going to flush both ITLB and DTLB
if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries || !gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

static void mpc601_dbat_update(uint32_t /*bat_reg*/)
Expand All@@ -1059,11 +1094,11 @@ static void ppc_ibat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
mmu_pat_ctx_changed();
}

static void ppc_dbat_update(uint32_t bat_reg)
Expand All@@ -1084,22 +1119,20 @@ static void ppc_dbat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

void mmu_pat_ctx_changed()
{
// Page address translation context changed so we need to flush
// all PAT entries from both ITLB and DTLB
if (!gTLBFlushIPatEntries || !gTLBFlushDPatEntries) {
gTLBFlushIPatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::DTLB>);
// Page address translation context changed so invalidate all PAT entries
// from both ITLB and DTLB.
if (!gTLBInvalidatePatEntries) {
gTLBInvalidatePatEntries = true;
add_ctx_sync_action(&tlb_invalidate_pat_entries);
}
}

Expand DownExpand Up@@ -1150,7 +1183,7 @@ inline T mmu_read_vmem(uint32_t opcode, uint32_t guest_va)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1321,7 +1354,7 @@ inline void mmu_write_vmem(uint32_t opcode, uint32_t guest_va, T value)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1895,7 +1928,7 @@ bool mmu_translate_dbg(uint32_t guest_va, uint32_t &guest_pa) {
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];

do {
if (tlb1_entry->tag != tag) {
if (!tlb1_entry->matches_tag(tag)) {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb<TLBType::DTLB>(guest_va, tag);
if (tlb2_entry == nullptr) {
Expand DownExpand Up@@ -1946,12 +1979,15 @@ static void invalidate_tlb_entries(std::array<TLBEntry, N> &tlb) {
tlb_el.host_va_offs_r = 0;
tlb_el.host_va_offs_w = 0;
tlb_el.phys_tag = 0;
tlb_el.reserved = 0;
tlb_el.pat_generation = 0;
}
}

void ppc_mmu_init()
{
gTLBPatGeneration = 0;
gTLBInvalidatePatEntries = false;

last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};

mmu_exception_handler = ppc_exception_handler;
Expand Down
34 changes: 0 additions & 34 deletions cpu/ppc/ppcmmu.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMMU_H
#define PPCMMU_H

#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <functional>

Expand DownExpand Up@@ -84,38 +82,6 @@ typedef struct MapDmaResult {
constexpr uint32_t PPC_PAGE_SIZE_BITS = 12;
constexpr uint32_t PPC_PAGE_SIZE = (1 << PPC_PAGE_SIZE_BITS);
constexpr uint32_t PPC_PAGE_MASK = ~(PPC_PAGE_SIZE - 1);
constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t reserved;
} TLBEntry;

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

extern std::function<void(uint32_t bat_reg)> ibat_update;
extern std::function<void(uint32_t bat_reg)> dbat_update;
Expand Down
1 change: 1 addition & 0 deletions devices/common/dbdma.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <cstring>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 98 additions & 62 deletions cpu/ppc/ppcmmu.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,58 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio, bool
return MapDmaResult{RT_NONE, false, nullptr, nullptr, 0};
}

constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

// PAT context changes are frequent, so implicitly invalidate PAT-derived
// entries via a generation counter (instead of walking the TLB array and
// clearing every time).
static uint32_t gTLBPatGeneration = 0;

typedef struct TLBEntry {
uint32_t tag; // use is_invalid() or matches_tag() for validity checks
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t pat_generation;

bool is_invalid() const
{
return tag == TLB_INVALID_TAG ||
((flags & TLBFlags::TLBE_FROM_PAT) &&
pat_generation != gTLBPatGeneration);
}

bool matches_tag(uint32_t tag_in) const
{
return tag == tag_in &&
(!(flags & TLBFlags::TLBE_FROM_PAT) ||
pat_generation == gTLBPatGeneration);
}
} TLBEntry;

// primary ITLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> itlb1_mode1;
static std::array<TLBEntry, TLB_SIZE> itlb1_mode2;
Expand DownExpand Up@@ -555,28 +607,28 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
}

// select the target from invalid blocks first
if (tlb_entry[0].tag == TLB_INVALID_TAG) {
if (tlb_entry[0].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return tlb_entry;
} else if (tlb_entry[1].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[1].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return &tlb_entry[1];
} else if (tlb_entry[2].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[2].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
return &tlb_entry[2];
} else if (tlb_entry[3].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[3].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -666,6 +718,7 @@ static TLBEntry* itlb2_refill(uint32_t guest_va)
tlb_entry->host_va_offs_r = (int64_t)rgn_desc->mem_ptr - guest_va +
(phys_addr - rgn_desc->start);
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
} else {
ABORT_F("Instruction fetch from unmapped memory at 0x%08X!\n", phys_addr);
}
Expand DownExpand Up@@ -749,6 +802,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write, bool is_dbg = fal
}
}
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
return tlb_entry;
} else {
if (!is_dbg) {
Expand DownExpand Up@@ -777,27 +831,27 @@ static inline TLBEntry* lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
tlb_entry = &pCurDTLB2[((guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask) * TLB2_WAYS];
}

if (tlb_entry->tag == tag) {
if (tlb_entry[0].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
} else if (tlb_entry[1].tag == tag) {
} else if (tlb_entry[1].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
tlb_entry = &tlb_entry[1];
} else if (tlb_entry[2].tag == tag) {
} else if (tlb_entry[2].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
tlb_entry = &tlb_entry[2];
} else if (tlb_entry[3].tag == tag) {
} else if (tlb_entry[3].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -829,7 +883,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)

// look up guest virtual address in the primary ITLB
tlb1_entry = &pCurITLB1[(vaddr >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary ITLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary ITLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_itlb_hits++;
#endif
Expand All@@ -855,6 +909,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r;
tlb1_entry->phys_tag = tlb2_entry->phys_tag;
tlb1_entry->pat_generation = tlb2_entry->pat_generation;
host_va = (uint8_t *)(tlb1_entry->host_va_offs_r + vaddr);
}

Expand DownExpand Up@@ -940,10 +995,9 @@ void tlb_flush_entries(TLBFlags type)
}
}

bool gTLBFlushIBatEntries = false;
bool gTLBFlushDBatEntries = false;
bool gTLBFlushIPatEntries = false;
bool gTLBFlushDPatEntries = false;
static bool gTLBFlushIBatEntries = false;
static bool gTLBFlushDBatEntries = false;
static bool gTLBInvalidatePatEntries = false;

template <const TLBType tlb_type>
void tlb_flush_bat_entries()
Expand All@@ -961,38 +1015,18 @@ void tlb_flush_bat_entries()
}
}

template <const TLBType tlb_type>
void tlb_flush_pat_entries()
static void tlb_invalidate_pat_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIPatEntries)
return;
if (!gTLBInvalidatePatEntries)
return;

gTLBPatGeneration++;
if (gTLBPatGeneration == 0) { // Do a full flush when the counter wraps around
tlb_flush_entries<TLBType::ITLB>(TLBE_FROM_PAT);
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>(TLBE_FROM_PAT);
gTLBFlushDPatEntries = false;
}
}

template <const TLBType tlb_type>
void tlb_flush_all_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIBatEntries && !gTLBFlushIPatEntries)
return;
tlb_flush_entries<TLBType::ITLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushIBatEntries = false;
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDBatEntries && !gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushDBatEntries = false;
gTLBFlushDPatEntries = false;
}
gTLBInvalidatePatEntries = false;
}

static void mpc601_bat_update(uint32_t bat_reg)
Expand DownExpand Up@@ -1026,14 +1060,15 @@ static void mpc601_bat_update(uint32_t bat_reg)
}

// MPC601 has unified BATs so we're going to flush both ITLB and DTLB
if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries || !gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

static void mpc601_dbat_update(uint32_t /*bat_reg*/)
Expand All@@ -1059,11 +1094,11 @@ static void ppc_ibat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
mmu_pat_ctx_changed();
}

static void ppc_dbat_update(uint32_t bat_reg)
Expand All@@ -1084,22 +1119,20 @@ static void ppc_dbat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

void mmu_pat_ctx_changed()
{
// Page address translation context changed so we need to flush
// all PAT entries from both ITLB and DTLB
if (!gTLBFlushIPatEntries || !gTLBFlushDPatEntries) {
gTLBFlushIPatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::DTLB>);
// Page address translation context changed so invalidate all PAT entries
// from both ITLB and DTLB.
if (!gTLBInvalidatePatEntries) {
gTLBInvalidatePatEntries = true;
add_ctx_sync_action(&tlb_invalidate_pat_entries);
}
}

Expand DownExpand Up@@ -1150,7 +1183,7 @@ inline T mmu_read_vmem(uint32_t opcode, uint32_t guest_va)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1321,7 +1354,7 @@ inline void mmu_write_vmem(uint32_t opcode, uint32_t guest_va, T value)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1895,7 +1928,7 @@ bool mmu_translate_dbg(uint32_t guest_va, uint32_t &guest_pa) {
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];

do {
if (tlb1_entry->tag != tag) {
if (!tlb1_entry->matches_tag(tag)) {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb<TLBType::DTLB>(guest_va, tag);
if (tlb2_entry == nullptr) {
Expand DownExpand Up@@ -1946,12 +1979,15 @@ static void invalidate_tlb_entries(std::array<TLBEntry, N> &tlb) {
tlb_el.host_va_offs_r = 0;
tlb_el.host_va_offs_w = 0;
tlb_el.phys_tag = 0;
tlb_el.reserved = 0;
tlb_el.pat_generation = 0;
}
}

void ppc_mmu_init()
{
gTLBPatGeneration = 0;
gTLBInvalidatePatEntries = false;

last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};

mmu_exception_handler = ppc_exception_handler;
Expand Down
34 changes: 0 additions & 34 deletions cpu/ppc/ppcmmu.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMMU_H
#define PPCMMU_H

#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <functional>

Expand DownExpand Up@@ -84,38 +82,6 @@ typedef struct MapDmaResult {
constexpr uint32_t PPC_PAGE_SIZE_BITS = 12;
constexpr uint32_t PPC_PAGE_SIZE = (1 << PPC_PAGE_SIZE_BITS);
constexpr uint32_t PPC_PAGE_MASK = ~(PPC_PAGE_SIZE - 1);
constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t reserved;
} TLBEntry;

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

extern std::function<void(uint32_t bat_reg)> ibat_update;
extern std::function<void(uint32_t bat_reg)> dbat_update;
Expand Down
1 change: 1 addition & 0 deletions devices/common/dbdma.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <cstring>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 98 additions & 62 deletions cpu/ppc/ppcmmu.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,58 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio, bool
return MapDmaResult{RT_NONE, false, nullptr, nullptr, 0};
}

constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

// PAT context changes are frequent, so implicitly invalidate PAT-derived
// entries via a generation counter (instead of walking the TLB array and
// clearing every time).
static uint32_t gTLBPatGeneration = 0;

typedef struct TLBEntry {
uint32_t tag; // use is_invalid() or matches_tag() for validity checks
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t pat_generation;

bool is_invalid() const
{
return tag == TLB_INVALID_TAG ||
((flags & TLBFlags::TLBE_FROM_PAT) &&
pat_generation != gTLBPatGeneration);
}

bool matches_tag(uint32_t tag_in) const
{
return tag == tag_in &&
(!(flags & TLBFlags::TLBE_FROM_PAT) ||
pat_generation == gTLBPatGeneration);
}
} TLBEntry;

// primary ITLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> itlb1_mode1;
static std::array<TLBEntry, TLB_SIZE> itlb1_mode2;
Expand DownExpand Up@@ -555,28 +607,28 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
}

// select the target from invalid blocks first
if (tlb_entry[0].tag == TLB_INVALID_TAG) {
if (tlb_entry[0].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return tlb_entry;
} else if (tlb_entry[1].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[1].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return &tlb_entry[1];
} else if (tlb_entry[2].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[2].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
return &tlb_entry[2];
} else if (tlb_entry[3].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[3].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -666,6 +718,7 @@ static TLBEntry* itlb2_refill(uint32_t guest_va)
tlb_entry->host_va_offs_r = (int64_t)rgn_desc->mem_ptr - guest_va +
(phys_addr - rgn_desc->start);
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
} else {
ABORT_F("Instruction fetch from unmapped memory at 0x%08X!\n", phys_addr);
}
Expand DownExpand Up@@ -749,6 +802,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write, bool is_dbg = fal
}
}
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
return tlb_entry;
} else {
if (!is_dbg) {
Expand DownExpand Up@@ -777,27 +831,27 @@ static inline TLBEntry* lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
tlb_entry = &pCurDTLB2[((guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask) * TLB2_WAYS];
}

if (tlb_entry->tag == tag) {
if (tlb_entry[0].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
} else if (tlb_entry[1].tag == tag) {
} else if (tlb_entry[1].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
tlb_entry = &tlb_entry[1];
} else if (tlb_entry[2].tag == tag) {
} else if (tlb_entry[2].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
tlb_entry = &tlb_entry[2];
} else if (tlb_entry[3].tag == tag) {
} else if (tlb_entry[3].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -829,7 +883,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)

// look up guest virtual address in the primary ITLB
tlb1_entry = &pCurITLB1[(vaddr >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary ITLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary ITLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_itlb_hits++;
#endif
Expand All@@ -855,6 +909,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r;
tlb1_entry->phys_tag = tlb2_entry->phys_tag;
tlb1_entry->pat_generation = tlb2_entry->pat_generation;
host_va = (uint8_t *)(tlb1_entry->host_va_offs_r + vaddr);
}

Expand DownExpand Up@@ -940,10 +995,9 @@ void tlb_flush_entries(TLBFlags type)
}
}

bool gTLBFlushIBatEntries = false;
bool gTLBFlushDBatEntries = false;
bool gTLBFlushIPatEntries = false;
bool gTLBFlushDPatEntries = false;
static bool gTLBFlushIBatEntries = false;
static bool gTLBFlushDBatEntries = false;
static bool gTLBInvalidatePatEntries = false;

template <const TLBType tlb_type>
void tlb_flush_bat_entries()
Expand All@@ -961,38 +1015,18 @@ void tlb_flush_bat_entries()
}
}

template <const TLBType tlb_type>
void tlb_flush_pat_entries()
static void tlb_invalidate_pat_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIPatEntries)
return;
if (!gTLBInvalidatePatEntries)
return;

gTLBPatGeneration++;
if (gTLBPatGeneration == 0) { // Do a full flush when the counter wraps around
tlb_flush_entries<TLBType::ITLB>(TLBE_FROM_PAT);
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>(TLBE_FROM_PAT);
gTLBFlushDPatEntries = false;
}
}

template <const TLBType tlb_type>
void tlb_flush_all_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIBatEntries && !gTLBFlushIPatEntries)
return;
tlb_flush_entries<TLBType::ITLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushIBatEntries = false;
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDBatEntries && !gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushDBatEntries = false;
gTLBFlushDPatEntries = false;
}
gTLBInvalidatePatEntries = false;
}

static void mpc601_bat_update(uint32_t bat_reg)
Expand DownExpand Up@@ -1026,14 +1060,15 @@ static void mpc601_bat_update(uint32_t bat_reg)
}

// MPC601 has unified BATs so we're going to flush both ITLB and DTLB
if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries || !gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

static void mpc601_dbat_update(uint32_t /*bat_reg*/)
Expand All@@ -1059,11 +1094,11 @@ static void ppc_ibat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
mmu_pat_ctx_changed();
}

static void ppc_dbat_update(uint32_t bat_reg)
Expand All@@ -1084,22 +1119,20 @@ static void ppc_dbat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

void mmu_pat_ctx_changed()
{
// Page address translation context changed so we need to flush
// all PAT entries from both ITLB and DTLB
if (!gTLBFlushIPatEntries || !gTLBFlushDPatEntries) {
gTLBFlushIPatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::DTLB>);
// Page address translation context changed so invalidate all PAT entries
// from both ITLB and DTLB.
if (!gTLBInvalidatePatEntries) {
gTLBInvalidatePatEntries = true;
add_ctx_sync_action(&tlb_invalidate_pat_entries);
}
}

Expand DownExpand Up@@ -1150,7 +1183,7 @@ inline T mmu_read_vmem(uint32_t opcode, uint32_t guest_va)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1321,7 +1354,7 @@ inline void mmu_write_vmem(uint32_t opcode, uint32_t guest_va, T value)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1895,7 +1928,7 @@ bool mmu_translate_dbg(uint32_t guest_va, uint32_t &guest_pa) {
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];

do {
if (tlb1_entry->tag != tag) {
if (!tlb1_entry->matches_tag(tag)) {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb<TLBType::DTLB>(guest_va, tag);
if (tlb2_entry == nullptr) {
Expand DownExpand Up@@ -1946,12 +1979,15 @@ static void invalidate_tlb_entries(std::array<TLBEntry, N> &tlb) {
tlb_el.host_va_offs_r = 0;
tlb_el.host_va_offs_w = 0;
tlb_el.phys_tag = 0;
tlb_el.reserved = 0;
tlb_el.pat_generation = 0;
}
}

void ppc_mmu_init()
{
gTLBPatGeneration = 0;
gTLBInvalidatePatEntries = false;

last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};

mmu_exception_handler = ppc_exception_handler;
Expand Down
34 changes: 0 additions & 34 deletions cpu/ppc/ppcmmu.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMMU_H
#define PPCMMU_H

#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <functional>

Expand DownExpand Up@@ -84,38 +82,6 @@ typedef struct MapDmaResult {
constexpr uint32_t PPC_PAGE_SIZE_BITS = 12;
constexpr uint32_t PPC_PAGE_SIZE = (1 << PPC_PAGE_SIZE_BITS);
constexpr uint32_t PPC_PAGE_MASK = ~(PPC_PAGE_SIZE - 1);
constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t reserved;
} TLBEntry;

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

extern std::function<void(uint32_t bat_reg)> ibat_update;
extern std::function<void(uint32_t bat_reg)> dbat_update;
Expand Down
1 change: 1 addition & 0 deletions devices/common/dbdma.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <cstring>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 98 additions & 62 deletions cpu/ppc/ppcmmu.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,58 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio, bool
return MapDmaResult{RT_NONE, false, nullptr, nullptr, 0};
}

constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

// PAT context changes are frequent, so implicitly invalidate PAT-derived
// entries via a generation counter (instead of walking the TLB array and
// clearing every time).
static uint32_t gTLBPatGeneration = 0;

typedef struct TLBEntry {
uint32_t tag; // use is_invalid() or matches_tag() for validity checks
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t pat_generation;

bool is_invalid() const
{
return tag == TLB_INVALID_TAG ||
((flags & TLBFlags::TLBE_FROM_PAT) &&
pat_generation != gTLBPatGeneration);
}

bool matches_tag(uint32_t tag_in) const
{
return tag == tag_in &&
(!(flags & TLBFlags::TLBE_FROM_PAT) ||
pat_generation == gTLBPatGeneration);
}
} TLBEntry;

// primary ITLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> itlb1_mode1;
static std::array<TLBEntry, TLB_SIZE> itlb1_mode2;
Expand DownExpand Up@@ -555,28 +607,28 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
}

// select the target from invalid blocks first
if (tlb_entry[0].tag == TLB_INVALID_TAG) {
if (tlb_entry[0].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return tlb_entry;
} else if (tlb_entry[1].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[1].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return &tlb_entry[1];
} else if (tlb_entry[2].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[2].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
return &tlb_entry[2];
} else if (tlb_entry[3].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[3].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -666,6 +718,7 @@ static TLBEntry* itlb2_refill(uint32_t guest_va)
tlb_entry->host_va_offs_r = (int64_t)rgn_desc->mem_ptr - guest_va +
(phys_addr - rgn_desc->start);
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
} else {
ABORT_F("Instruction fetch from unmapped memory at 0x%08X!\n", phys_addr);
}
Expand DownExpand Up@@ -749,6 +802,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write, bool is_dbg = fal
}
}
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
return tlb_entry;
} else {
if (!is_dbg) {
Expand DownExpand Up@@ -777,27 +831,27 @@ static inline TLBEntry* lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
tlb_entry = &pCurDTLB2[((guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask) * TLB2_WAYS];
}

if (tlb_entry->tag == tag) {
if (tlb_entry[0].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
} else if (tlb_entry[1].tag == tag) {
} else if (tlb_entry[1].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
tlb_entry = &tlb_entry[1];
} else if (tlb_entry[2].tag == tag) {
} else if (tlb_entry[2].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
tlb_entry = &tlb_entry[2];
} else if (tlb_entry[3].tag == tag) {
} else if (tlb_entry[3].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -829,7 +883,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)

// look up guest virtual address in the primary ITLB
tlb1_entry = &pCurITLB1[(vaddr >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary ITLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary ITLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_itlb_hits++;
#endif
Expand All@@ -855,6 +909,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r;
tlb1_entry->phys_tag = tlb2_entry->phys_tag;
tlb1_entry->pat_generation = tlb2_entry->pat_generation;
host_va = (uint8_t *)(tlb1_entry->host_va_offs_r + vaddr);
}

Expand DownExpand Up@@ -940,10 +995,9 @@ void tlb_flush_entries(TLBFlags type)
}
}

bool gTLBFlushIBatEntries = false;
bool gTLBFlushDBatEntries = false;
bool gTLBFlushIPatEntries = false;
bool gTLBFlushDPatEntries = false;
static bool gTLBFlushIBatEntries = false;
static bool gTLBFlushDBatEntries = false;
static bool gTLBInvalidatePatEntries = false;

template <const TLBType tlb_type>
void tlb_flush_bat_entries()
Expand All@@ -961,38 +1015,18 @@ void tlb_flush_bat_entries()
}
}

template <const TLBType tlb_type>
void tlb_flush_pat_entries()
static void tlb_invalidate_pat_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIPatEntries)
return;
if (!gTLBInvalidatePatEntries)
return;

gTLBPatGeneration++;
if (gTLBPatGeneration == 0) { // Do a full flush when the counter wraps around
tlb_flush_entries<TLBType::ITLB>(TLBE_FROM_PAT);
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>(TLBE_FROM_PAT);
gTLBFlushDPatEntries = false;
}
}

template <const TLBType tlb_type>
void tlb_flush_all_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIBatEntries && !gTLBFlushIPatEntries)
return;
tlb_flush_entries<TLBType::ITLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushIBatEntries = false;
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDBatEntries && !gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushDBatEntries = false;
gTLBFlushDPatEntries = false;
}
gTLBInvalidatePatEntries = false;
}

static void mpc601_bat_update(uint32_t bat_reg)
Expand DownExpand Up@@ -1026,14 +1060,15 @@ static void mpc601_bat_update(uint32_t bat_reg)
}

// MPC601 has unified BATs so we're going to flush both ITLB and DTLB
if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries || !gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

static void mpc601_dbat_update(uint32_t /*bat_reg*/)
Expand All@@ -1059,11 +1094,11 @@ static void ppc_ibat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
mmu_pat_ctx_changed();
}

static void ppc_dbat_update(uint32_t bat_reg)
Expand All@@ -1084,22 +1119,20 @@ static void ppc_dbat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

void mmu_pat_ctx_changed()
{
// Page address translation context changed so we need to flush
// all PAT entries from both ITLB and DTLB
if (!gTLBFlushIPatEntries || !gTLBFlushDPatEntries) {
gTLBFlushIPatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::DTLB>);
// Page address translation context changed so invalidate all PAT entries
// from both ITLB and DTLB.
if (!gTLBInvalidatePatEntries) {
gTLBInvalidatePatEntries = true;
add_ctx_sync_action(&tlb_invalidate_pat_entries);
}
}

Expand DownExpand Up@@ -1150,7 +1183,7 @@ inline T mmu_read_vmem(uint32_t opcode, uint32_t guest_va)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1321,7 +1354,7 @@ inline void mmu_write_vmem(uint32_t opcode, uint32_t guest_va, T value)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1895,7 +1928,7 @@ bool mmu_translate_dbg(uint32_t guest_va, uint32_t &guest_pa) {
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];

do {
if (tlb1_entry->tag != tag) {
if (!tlb1_entry->matches_tag(tag)) {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb<TLBType::DTLB>(guest_va, tag);
if (tlb2_entry == nullptr) {
Expand DownExpand Up@@ -1946,12 +1979,15 @@ static void invalidate_tlb_entries(std::array<TLBEntry, N> &tlb) {
tlb_el.host_va_offs_r = 0;
tlb_el.host_va_offs_w = 0;
tlb_el.phys_tag = 0;
tlb_el.reserved = 0;
tlb_el.pat_generation = 0;
}
}

void ppc_mmu_init()
{
gTLBPatGeneration = 0;
gTLBInvalidatePatEntries = false;

last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};

mmu_exception_handler = ppc_exception_handler;
Expand Down
34 changes: 0 additions & 34 deletions cpu/ppc/ppcmmu.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMMU_H
#define PPCMMU_H

#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <functional>

Expand DownExpand Up@@ -84,38 +82,6 @@ typedef struct MapDmaResult {
constexpr uint32_t PPC_PAGE_SIZE_BITS = 12;
constexpr uint32_t PPC_PAGE_SIZE = (1 << PPC_PAGE_SIZE_BITS);
constexpr uint32_t PPC_PAGE_MASK = ~(PPC_PAGE_SIZE - 1);
constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t reserved;
} TLBEntry;

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

extern std::function<void(uint32_t bat_reg)> ibat_update;
extern std::function<void(uint32_t bat_reg)> dbat_update;
Expand Down
1 change: 1 addition & 0 deletions devices/common/dbdma.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <cstring>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 98 additions & 62 deletions cpu/ppc/ppcmmu.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,58 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio, bool
return MapDmaResult{RT_NONE, false, nullptr, nullptr, 0};
}

constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

// PAT context changes are frequent, so implicitly invalidate PAT-derived
// entries via a generation counter (instead of walking the TLB array and
// clearing every time).
static uint32_t gTLBPatGeneration = 0;

typedef struct TLBEntry {
uint32_t tag; // use is_invalid() or matches_tag() for validity checks
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t pat_generation;

bool is_invalid() const
{
return tag == TLB_INVALID_TAG ||
((flags & TLBFlags::TLBE_FROM_PAT) &&
pat_generation != gTLBPatGeneration);
}

bool matches_tag(uint32_t tag_in) const
{
return tag == tag_in &&
(!(flags & TLBFlags::TLBE_FROM_PAT) ||
pat_generation == gTLBPatGeneration);
}
} TLBEntry;

// primary ITLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> itlb1_mode1;
static std::array<TLBEntry, TLB_SIZE> itlb1_mode2;
Expand DownExpand Up@@ -555,28 +607,28 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
}

// select the target from invalid blocks first
if (tlb_entry[0].tag == TLB_INVALID_TAG) {
if (tlb_entry[0].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return tlb_entry;
} else if (tlb_entry[1].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[1].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return &tlb_entry[1];
} else if (tlb_entry[2].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[2].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
return &tlb_entry[2];
} else if (tlb_entry[3].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[3].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -666,6 +718,7 @@ static TLBEntry* itlb2_refill(uint32_t guest_va)
tlb_entry->host_va_offs_r = (int64_t)rgn_desc->mem_ptr - guest_va +
(phys_addr - rgn_desc->start);
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
} else {
ABORT_F("Instruction fetch from unmapped memory at 0x%08X!\n", phys_addr);
}
Expand DownExpand Up@@ -749,6 +802,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write, bool is_dbg = fal
}
}
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
return tlb_entry;
} else {
if (!is_dbg) {
Expand DownExpand Up@@ -777,27 +831,27 @@ static inline TLBEntry* lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
tlb_entry = &pCurDTLB2[((guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask) * TLB2_WAYS];
}

if (tlb_entry->tag == tag) {
if (tlb_entry[0].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
} else if (tlb_entry[1].tag == tag) {
} else if (tlb_entry[1].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
tlb_entry = &tlb_entry[1];
} else if (tlb_entry[2].tag == tag) {
} else if (tlb_entry[2].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
tlb_entry = &tlb_entry[2];
} else if (tlb_entry[3].tag == tag) {
} else if (tlb_entry[3].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -829,7 +883,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)

// look up guest virtual address in the primary ITLB
tlb1_entry = &pCurITLB1[(vaddr >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary ITLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary ITLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_itlb_hits++;
#endif
Expand All@@ -855,6 +909,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r;
tlb1_entry->phys_tag = tlb2_entry->phys_tag;
tlb1_entry->pat_generation = tlb2_entry->pat_generation;
host_va = (uint8_t *)(tlb1_entry->host_va_offs_r + vaddr);
}

Expand DownExpand Up@@ -940,10 +995,9 @@ void tlb_flush_entries(TLBFlags type)
}
}

bool gTLBFlushIBatEntries = false;
bool gTLBFlushDBatEntries = false;
bool gTLBFlushIPatEntries = false;
bool gTLBFlushDPatEntries = false;
static bool gTLBFlushIBatEntries = false;
static bool gTLBFlushDBatEntries = false;
static bool gTLBInvalidatePatEntries = false;

template <const TLBType tlb_type>
void tlb_flush_bat_entries()
Expand All@@ -961,38 +1015,18 @@ void tlb_flush_bat_entries()
}
}

template <const TLBType tlb_type>
void tlb_flush_pat_entries()
static void tlb_invalidate_pat_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIPatEntries)
return;
if (!gTLBInvalidatePatEntries)
return;

gTLBPatGeneration++;
if (gTLBPatGeneration == 0) { // Do a full flush when the counter wraps around
tlb_flush_entries<TLBType::ITLB>(TLBE_FROM_PAT);
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>(TLBE_FROM_PAT);
gTLBFlushDPatEntries = false;
}
}

template <const TLBType tlb_type>
void tlb_flush_all_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIBatEntries && !gTLBFlushIPatEntries)
return;
tlb_flush_entries<TLBType::ITLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushIBatEntries = false;
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDBatEntries && !gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushDBatEntries = false;
gTLBFlushDPatEntries = false;
}
gTLBInvalidatePatEntries = false;
}

static void mpc601_bat_update(uint32_t bat_reg)
Expand DownExpand Up@@ -1026,14 +1060,15 @@ static void mpc601_bat_update(uint32_t bat_reg)
}

// MPC601 has unified BATs so we're going to flush both ITLB and DTLB
if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries || !gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

static void mpc601_dbat_update(uint32_t /*bat_reg*/)
Expand All@@ -1059,11 +1094,11 @@ static void ppc_ibat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
mmu_pat_ctx_changed();
}

static void ppc_dbat_update(uint32_t bat_reg)
Expand All@@ -1084,22 +1119,20 @@ static void ppc_dbat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

void mmu_pat_ctx_changed()
{
// Page address translation context changed so we need to flush
// all PAT entries from both ITLB and DTLB
if (!gTLBFlushIPatEntries || !gTLBFlushDPatEntries) {
gTLBFlushIPatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::DTLB>);
// Page address translation context changed so invalidate all PAT entries
// from both ITLB and DTLB.
if (!gTLBInvalidatePatEntries) {
gTLBInvalidatePatEntries = true;
add_ctx_sync_action(&tlb_invalidate_pat_entries);
}
}

Expand DownExpand Up@@ -1150,7 +1183,7 @@ inline T mmu_read_vmem(uint32_t opcode, uint32_t guest_va)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1321,7 +1354,7 @@ inline void mmu_write_vmem(uint32_t opcode, uint32_t guest_va, T value)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1895,7 +1928,7 @@ bool mmu_translate_dbg(uint32_t guest_va, uint32_t &guest_pa) {
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];

do {
if (tlb1_entry->tag != tag) {
if (!tlb1_entry->matches_tag(tag)) {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb<TLBType::DTLB>(guest_va, tag);
if (tlb2_entry == nullptr) {
Expand DownExpand Up@@ -1946,12 +1979,15 @@ static void invalidate_tlb_entries(std::array<TLBEntry, N> &tlb) {
tlb_el.host_va_offs_r = 0;
tlb_el.host_va_offs_w = 0;
tlb_el.phys_tag = 0;
tlb_el.reserved = 0;
tlb_el.pat_generation = 0;
}
}

void ppc_mmu_init()
{
gTLBPatGeneration = 0;
gTLBInvalidatePatEntries = false;

last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};

mmu_exception_handler = ppc_exception_handler;
Expand Down
34 changes: 0 additions & 34 deletions cpu/ppc/ppcmmu.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMMU_H
#define PPCMMU_H

#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <functional>

Expand DownExpand Up@@ -84,38 +82,6 @@ typedef struct MapDmaResult {
constexpr uint32_t PPC_PAGE_SIZE_BITS = 12;
constexpr uint32_t PPC_PAGE_SIZE = (1 << PPC_PAGE_SIZE_BITS);
constexpr uint32_t PPC_PAGE_MASK = ~(PPC_PAGE_SIZE - 1);
constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t reserved;
} TLBEntry;

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

extern std::function<void(uint32_t bat_reg)> ibat_update;
extern std::function<void(uint32_t bat_reg)> dbat_update;
Expand Down
1 change: 1 addition & 0 deletions devices/common/dbdma.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <cstring>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 98 additions & 62 deletions cpu/ppc/ppcmmu.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,58 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio, bool
return MapDmaResult{RT_NONE, false, nullptr, nullptr, 0};
}

constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

// PAT context changes are frequent, so implicitly invalidate PAT-derived
// entries via a generation counter (instead of walking the TLB array and
// clearing every time).
static uint32_t gTLBPatGeneration = 0;

typedef struct TLBEntry {
uint32_t tag; // use is_invalid() or matches_tag() for validity checks
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t pat_generation;

bool is_invalid() const
{
return tag == TLB_INVALID_TAG ||
((flags & TLBFlags::TLBE_FROM_PAT) &&
pat_generation != gTLBPatGeneration);
}

bool matches_tag(uint32_t tag_in) const
{
return tag == tag_in &&
(!(flags & TLBFlags::TLBE_FROM_PAT) ||
pat_generation == gTLBPatGeneration);
}
} TLBEntry;

// primary ITLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> itlb1_mode1;
static std::array<TLBEntry, TLB_SIZE> itlb1_mode2;
Expand DownExpand Up@@ -555,28 +607,28 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
}

// select the target from invalid blocks first
if (tlb_entry[0].tag == TLB_INVALID_TAG) {
if (tlb_entry[0].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return tlb_entry;
} else if (tlb_entry[1].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[1].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return &tlb_entry[1];
} else if (tlb_entry[2].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[2].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
return &tlb_entry[2];
} else if (tlb_entry[3].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[3].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -666,6 +718,7 @@ static TLBEntry* itlb2_refill(uint32_t guest_va)
tlb_entry->host_va_offs_r = (int64_t)rgn_desc->mem_ptr - guest_va +
(phys_addr - rgn_desc->start);
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
} else {
ABORT_F("Instruction fetch from unmapped memory at 0x%08X!\n", phys_addr);
}
Expand DownExpand Up@@ -749,6 +802,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write, bool is_dbg = fal
}
}
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
return tlb_entry;
} else {
if (!is_dbg) {
Expand DownExpand Up@@ -777,27 +831,27 @@ static inline TLBEntry* lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
tlb_entry = &pCurDTLB2[((guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask) * TLB2_WAYS];
}

if (tlb_entry->tag == tag) {
if (tlb_entry[0].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
} else if (tlb_entry[1].tag == tag) {
} else if (tlb_entry[1].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
tlb_entry = &tlb_entry[1];
} else if (tlb_entry[2].tag == tag) {
} else if (tlb_entry[2].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
tlb_entry = &tlb_entry[2];
} else if (tlb_entry[3].tag == tag) {
} else if (tlb_entry[3].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -829,7 +883,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)

// look up guest virtual address in the primary ITLB
tlb1_entry = &pCurITLB1[(vaddr >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary ITLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary ITLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_itlb_hits++;
#endif
Expand All@@ -855,6 +909,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r;
tlb1_entry->phys_tag = tlb2_entry->phys_tag;
tlb1_entry->pat_generation = tlb2_entry->pat_generation;
host_va = (uint8_t *)(tlb1_entry->host_va_offs_r + vaddr);
}

Expand DownExpand Up@@ -940,10 +995,9 @@ void tlb_flush_entries(TLBFlags type)
}
}

bool gTLBFlushIBatEntries = false;
bool gTLBFlushDBatEntries = false;
bool gTLBFlushIPatEntries = false;
bool gTLBFlushDPatEntries = false;
static bool gTLBFlushIBatEntries = false;
static bool gTLBFlushDBatEntries = false;
static bool gTLBInvalidatePatEntries = false;

template <const TLBType tlb_type>
void tlb_flush_bat_entries()
Expand All@@ -961,38 +1015,18 @@ void tlb_flush_bat_entries()
}
}

template <const TLBType tlb_type>
void tlb_flush_pat_entries()
static void tlb_invalidate_pat_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIPatEntries)
return;
if (!gTLBInvalidatePatEntries)
return;

gTLBPatGeneration++;
if (gTLBPatGeneration == 0) { // Do a full flush when the counter wraps around
tlb_flush_entries<TLBType::ITLB>(TLBE_FROM_PAT);
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>(TLBE_FROM_PAT);
gTLBFlushDPatEntries = false;
}
}

template <const TLBType tlb_type>
void tlb_flush_all_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIBatEntries && !gTLBFlushIPatEntries)
return;
tlb_flush_entries<TLBType::ITLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushIBatEntries = false;
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDBatEntries && !gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushDBatEntries = false;
gTLBFlushDPatEntries = false;
}
gTLBInvalidatePatEntries = false;
}

static void mpc601_bat_update(uint32_t bat_reg)
Expand DownExpand Up@@ -1026,14 +1060,15 @@ static void mpc601_bat_update(uint32_t bat_reg)
}

// MPC601 has unified BATs so we're going to flush both ITLB and DTLB
if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries || !gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

static void mpc601_dbat_update(uint32_t /*bat_reg*/)
Expand All@@ -1059,11 +1094,11 @@ static void ppc_ibat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
mmu_pat_ctx_changed();
}

static void ppc_dbat_update(uint32_t bat_reg)
Expand All@@ -1084,22 +1119,20 @@ static void ppc_dbat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

void mmu_pat_ctx_changed()
{
// Page address translation context changed so we need to flush
// all PAT entries from both ITLB and DTLB
if (!gTLBFlushIPatEntries || !gTLBFlushDPatEntries) {
gTLBFlushIPatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::DTLB>);
// Page address translation context changed so invalidate all PAT entries
// from both ITLB and DTLB.
if (!gTLBInvalidatePatEntries) {
gTLBInvalidatePatEntries = true;
add_ctx_sync_action(&tlb_invalidate_pat_entries);
}
}

Expand DownExpand Up@@ -1150,7 +1183,7 @@ inline T mmu_read_vmem(uint32_t opcode, uint32_t guest_va)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1321,7 +1354,7 @@ inline void mmu_write_vmem(uint32_t opcode, uint32_t guest_va, T value)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1895,7 +1928,7 @@ bool mmu_translate_dbg(uint32_t guest_va, uint32_t &guest_pa) {
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];

do {
if (tlb1_entry->tag != tag) {
if (!tlb1_entry->matches_tag(tag)) {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb<TLBType::DTLB>(guest_va, tag);
if (tlb2_entry == nullptr) {
Expand DownExpand Up@@ -1946,12 +1979,15 @@ static void invalidate_tlb_entries(std::array<TLBEntry, N> &tlb) {
tlb_el.host_va_offs_r = 0;
tlb_el.host_va_offs_w = 0;
tlb_el.phys_tag = 0;
tlb_el.reserved = 0;
tlb_el.pat_generation = 0;
}
}

void ppc_mmu_init()
{
gTLBPatGeneration = 0;
gTLBInvalidatePatEntries = false;

last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};

mmu_exception_handler = ppc_exception_handler;
Expand Down
34 changes: 0 additions & 34 deletions cpu/ppc/ppcmmu.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMMU_H
#define PPCMMU_H

#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <functional>

Expand DownExpand Up@@ -84,38 +82,6 @@ typedef struct MapDmaResult {
constexpr uint32_t PPC_PAGE_SIZE_BITS = 12;
constexpr uint32_t PPC_PAGE_SIZE = (1 << PPC_PAGE_SIZE_BITS);
constexpr uint32_t PPC_PAGE_MASK = ~(PPC_PAGE_SIZE - 1);
constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t reserved;
} TLBEntry;

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

extern std::function<void(uint32_t bat_reg)> ibat_update;
extern std::function<void(uint32_t bat_reg)> dbat_update;
Expand Down
1 change: 1 addition & 0 deletions devices/common/dbdma.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <cstring>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 98 additions & 62 deletions cpu/ppc/ppcmmu.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,58 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio, bool
return MapDmaResult{RT_NONE, false, nullptr, nullptr, 0};
}

constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

// PAT context changes are frequent, so implicitly invalidate PAT-derived
// entries via a generation counter (instead of walking the TLB array and
// clearing every time).
static uint32_t gTLBPatGeneration = 0;

typedef struct TLBEntry {
uint32_t tag; // use is_invalid() or matches_tag() for validity checks
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t pat_generation;

bool is_invalid() const
{
return tag == TLB_INVALID_TAG ||
((flags & TLBFlags::TLBE_FROM_PAT) &&
pat_generation != gTLBPatGeneration);
}

bool matches_tag(uint32_t tag_in) const
{
return tag == tag_in &&
(!(flags & TLBFlags::TLBE_FROM_PAT) ||
pat_generation == gTLBPatGeneration);
}
} TLBEntry;

// primary ITLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> itlb1_mode1;
static std::array<TLBEntry, TLB_SIZE> itlb1_mode2;
Expand DownExpand Up@@ -555,28 +607,28 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
}

// select the target from invalid blocks first
if (tlb_entry[0].tag == TLB_INVALID_TAG) {
if (tlb_entry[0].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return tlb_entry;
} else if (tlb_entry[1].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[1].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return &tlb_entry[1];
} else if (tlb_entry[2].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[2].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
return &tlb_entry[2];
} else if (tlb_entry[3].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[3].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -666,6 +718,7 @@ static TLBEntry* itlb2_refill(uint32_t guest_va)
tlb_entry->host_va_offs_r = (int64_t)rgn_desc->mem_ptr - guest_va +
(phys_addr - rgn_desc->start);
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
} else {
ABORT_F("Instruction fetch from unmapped memory at 0x%08X!\n", phys_addr);
}
Expand DownExpand Up@@ -749,6 +802,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write, bool is_dbg = fal
}
}
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
return tlb_entry;
} else {
if (!is_dbg) {
Expand DownExpand Up@@ -777,27 +831,27 @@ static inline TLBEntry* lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
tlb_entry = &pCurDTLB2[((guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask) * TLB2_WAYS];
}

if (tlb_entry->tag == tag) {
if (tlb_entry[0].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
} else if (tlb_entry[1].tag == tag) {
} else if (tlb_entry[1].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
tlb_entry = &tlb_entry[1];
} else if (tlb_entry[2].tag == tag) {
} else if (tlb_entry[2].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
tlb_entry = &tlb_entry[2];
} else if (tlb_entry[3].tag == tag) {
} else if (tlb_entry[3].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -829,7 +883,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)

// look up guest virtual address in the primary ITLB
tlb1_entry = &pCurITLB1[(vaddr >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary ITLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary ITLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_itlb_hits++;
#endif
Expand All@@ -855,6 +909,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r;
tlb1_entry->phys_tag = tlb2_entry->phys_tag;
tlb1_entry->pat_generation = tlb2_entry->pat_generation;
host_va = (uint8_t *)(tlb1_entry->host_va_offs_r + vaddr);
}

Expand DownExpand Up@@ -940,10 +995,9 @@ void tlb_flush_entries(TLBFlags type)
}
}

bool gTLBFlushIBatEntries = false;
bool gTLBFlushDBatEntries = false;
bool gTLBFlushIPatEntries = false;
bool gTLBFlushDPatEntries = false;
static bool gTLBFlushIBatEntries = false;
static bool gTLBFlushDBatEntries = false;
static bool gTLBInvalidatePatEntries = false;

template <const TLBType tlb_type>
void tlb_flush_bat_entries()
Expand All@@ -961,38 +1015,18 @@ void tlb_flush_bat_entries()
}
}

template <const TLBType tlb_type>
void tlb_flush_pat_entries()
static void tlb_invalidate_pat_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIPatEntries)
return;
if (!gTLBInvalidatePatEntries)
return;

gTLBPatGeneration++;
if (gTLBPatGeneration == 0) { // Do a full flush when the counter wraps around
tlb_flush_entries<TLBType::ITLB>(TLBE_FROM_PAT);
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>(TLBE_FROM_PAT);
gTLBFlushDPatEntries = false;
}
}

template <const TLBType tlb_type>
void tlb_flush_all_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIBatEntries && !gTLBFlushIPatEntries)
return;
tlb_flush_entries<TLBType::ITLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushIBatEntries = false;
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDBatEntries && !gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushDBatEntries = false;
gTLBFlushDPatEntries = false;
}
gTLBInvalidatePatEntries = false;
}

static void mpc601_bat_update(uint32_t bat_reg)
Expand DownExpand Up@@ -1026,14 +1060,15 @@ static void mpc601_bat_update(uint32_t bat_reg)
}

// MPC601 has unified BATs so we're going to flush both ITLB and DTLB
if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries || !gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

static void mpc601_dbat_update(uint32_t /*bat_reg*/)
Expand All@@ -1059,11 +1094,11 @@ static void ppc_ibat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
mmu_pat_ctx_changed();
}

static void ppc_dbat_update(uint32_t bat_reg)
Expand All@@ -1084,22 +1119,20 @@ static void ppc_dbat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

void mmu_pat_ctx_changed()
{
// Page address translation context changed so we need to flush
// all PAT entries from both ITLB and DTLB
if (!gTLBFlushIPatEntries || !gTLBFlushDPatEntries) {
gTLBFlushIPatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::DTLB>);
// Page address translation context changed so invalidate all PAT entries
// from both ITLB and DTLB.
if (!gTLBInvalidatePatEntries) {
gTLBInvalidatePatEntries = true;
add_ctx_sync_action(&tlb_invalidate_pat_entries);
}
}

Expand DownExpand Up@@ -1150,7 +1183,7 @@ inline T mmu_read_vmem(uint32_t opcode, uint32_t guest_va)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1321,7 +1354,7 @@ inline void mmu_write_vmem(uint32_t opcode, uint32_t guest_va, T value)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1895,7 +1928,7 @@ bool mmu_translate_dbg(uint32_t guest_va, uint32_t &guest_pa) {
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];

do {
if (tlb1_entry->tag != tag) {
if (!tlb1_entry->matches_tag(tag)) {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb<TLBType::DTLB>(guest_va, tag);
if (tlb2_entry == nullptr) {
Expand DownExpand Up@@ -1946,12 +1979,15 @@ static void invalidate_tlb_entries(std::array<TLBEntry, N> &tlb) {
tlb_el.host_va_offs_r = 0;
tlb_el.host_va_offs_w = 0;
tlb_el.phys_tag = 0;
tlb_el.reserved = 0;
tlb_el.pat_generation = 0;
}
}

void ppc_mmu_init()
{
gTLBPatGeneration = 0;
gTLBInvalidatePatEntries = false;

last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};

mmu_exception_handler = ppc_exception_handler;
Expand Down
34 changes: 0 additions & 34 deletions cpu/ppc/ppcmmu.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMMU_H
#define PPCMMU_H

#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <functional>

Expand DownExpand Up@@ -84,38 +82,6 @@ typedef struct MapDmaResult {
constexpr uint32_t PPC_PAGE_SIZE_BITS = 12;
constexpr uint32_t PPC_PAGE_SIZE = (1 << PPC_PAGE_SIZE_BITS);
constexpr uint32_t PPC_PAGE_MASK = ~(PPC_PAGE_SIZE - 1);
constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t reserved;
} TLBEntry;

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

extern std::function<void(uint32_t bat_reg)> ibat_update;
extern std::function<void(uint32_t bat_reg)> dbat_update;
Expand Down
1 change: 1 addition & 0 deletions devices/common/dbdma.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <cstring>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 98 additions & 62 deletions cpu/ppc/ppcmmu.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,58 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio, bool
return MapDmaResult{RT_NONE, false, nullptr, nullptr, 0};
}

constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

// PAT context changes are frequent, so implicitly invalidate PAT-derived
// entries via a generation counter (instead of walking the TLB array and
// clearing every time).
static uint32_t gTLBPatGeneration = 0;

typedef struct TLBEntry {
uint32_t tag; // use is_invalid() or matches_tag() for validity checks
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t pat_generation;

bool is_invalid() const
{
return tag == TLB_INVALID_TAG ||
((flags & TLBFlags::TLBE_FROM_PAT) &&
pat_generation != gTLBPatGeneration);
}

bool matches_tag(uint32_t tag_in) const
{
return tag == tag_in &&
(!(flags & TLBFlags::TLBE_FROM_PAT) ||
pat_generation == gTLBPatGeneration);
}
} TLBEntry;

// primary ITLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> itlb1_mode1;
static std::array<TLBEntry, TLB_SIZE> itlb1_mode2;
Expand DownExpand Up@@ -555,28 +607,28 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
}

// select the target from invalid blocks first
if (tlb_entry[0].tag == TLB_INVALID_TAG) {
if (tlb_entry[0].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return tlb_entry;
} else if (tlb_entry[1].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[1].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
return &tlb_entry[1];
} else if (tlb_entry[2].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[2].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
return &tlb_entry[2];
} else if (tlb_entry[3].tag == TLB_INVALID_TAG) {
} else if (tlb_entry[3].is_invalid()) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -666,6 +718,7 @@ static TLBEntry* itlb2_refill(uint32_t guest_va)
tlb_entry->host_va_offs_r = (int64_t)rgn_desc->mem_ptr - guest_va +
(phys_addr - rgn_desc->start);
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
} else {
ABORT_F("Instruction fetch from unmapped memory at 0x%08X!\n", phys_addr);
}
Expand DownExpand Up@@ -749,6 +802,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write, bool is_dbg = fal
}
}
tlb_entry->phys_tag = phys_addr & ~0xFFFUL;
tlb_entry->pat_generation = gTLBPatGeneration;
return tlb_entry;
} else {
if (!is_dbg) {
Expand DownExpand Up@@ -777,27 +831,27 @@ static inline TLBEntry* lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
tlb_entry = &pCurDTLB2[((guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask) * TLB2_WAYS];
}

if (tlb_entry->tag == tag) {
if (tlb_entry[0].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x3;
tlb_entry[1].lru_bits = 0x2;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
} else if (tlb_entry[1].tag == tag) {
} else if (tlb_entry[1].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits = 0x2;
tlb_entry[1].lru_bits = 0x3;
tlb_entry[2].lru_bits &= 0x1;
tlb_entry[3].lru_bits &= 0x1;
tlb_entry = &tlb_entry[1];
} else if (tlb_entry[2].tag == tag) {
} else if (tlb_entry[2].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
tlb_entry[2].lru_bits = 0x3;
tlb_entry[3].lru_bits = 0x2;
tlb_entry = &tlb_entry[2];
} else if (tlb_entry[3].tag == tag) {
} else if (tlb_entry[3].matches_tag(tag)) {
// update LRU bits
tlb_entry[0].lru_bits &= 0x1;
tlb_entry[1].lru_bits &= 0x1;
Expand DownExpand Up@@ -829,7 +883,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)

// look up guest virtual address in the primary ITLB
tlb1_entry = &pCurITLB1[(vaddr >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary ITLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary ITLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_itlb_hits++;
#endif
Expand All@@ -855,6 +909,7 @@ uint8_t *mmu_translate_imem(uint32_t vaddr, uint32_t *paddr)
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r;
tlb1_entry->phys_tag = tlb2_entry->phys_tag;
tlb1_entry->pat_generation = tlb2_entry->pat_generation;
host_va = (uint8_t *)(tlb1_entry->host_va_offs_r + vaddr);
}

Expand DownExpand Up@@ -940,10 +995,9 @@ void tlb_flush_entries(TLBFlags type)
}
}

bool gTLBFlushIBatEntries = false;
bool gTLBFlushDBatEntries = false;
bool gTLBFlushIPatEntries = false;
bool gTLBFlushDPatEntries = false;
static bool gTLBFlushIBatEntries = false;
static bool gTLBFlushDBatEntries = false;
static bool gTLBInvalidatePatEntries = false;

template <const TLBType tlb_type>
void tlb_flush_bat_entries()
Expand All@@ -961,38 +1015,18 @@ void tlb_flush_bat_entries()
}
}

template <const TLBType tlb_type>
void tlb_flush_pat_entries()
static void tlb_invalidate_pat_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIPatEntries)
return;
if (!gTLBInvalidatePatEntries)
return;

gTLBPatGeneration++;
if (gTLBPatGeneration == 0) { // Do a full flush when the counter wraps around
tlb_flush_entries<TLBType::ITLB>(TLBE_FROM_PAT);
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>(TLBE_FROM_PAT);
gTLBFlushDPatEntries = false;
}
}

template <const TLBType tlb_type>
void tlb_flush_all_entries()
{
if (tlb_type == TLBType::ITLB) {
if (!gTLBFlushIBatEntries && !gTLBFlushIPatEntries)
return;
tlb_flush_entries<TLBType::ITLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushIBatEntries = false;
gTLBFlushIPatEntries = false;
} else {
if (!gTLBFlushDBatEntries && !gTLBFlushDPatEntries)
return;
tlb_flush_entries<TLBType::DTLB>((TLBFlags)(TLBE_FROM_BAT | TLBE_FROM_PAT));
gTLBFlushDBatEntries = false;
gTLBFlushDPatEntries = false;
}
gTLBInvalidatePatEntries = false;
}

static void mpc601_bat_update(uint32_t bat_reg)
Expand DownExpand Up@@ -1026,14 +1060,15 @@ static void mpc601_bat_update(uint32_t bat_reg)
}

// MPC601 has unified BATs so we're going to flush both ITLB and DTLB
if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries || !gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

static void mpc601_dbat_update(uint32_t /*bat_reg*/)
Expand All@@ -1059,11 +1094,11 @@ static void ppc_ibat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushIBatEntries || !gTLBFlushIPatEntries) {
if (!gTLBFlushIBatEntries) {
gTLBFlushIBatEntries = true;
gTLBFlushIPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::ITLB>);
}
mmu_pat_ctx_changed();
}

static void ppc_dbat_update(uint32_t bat_reg)
Expand All@@ -1084,22 +1119,20 @@ static void ppc_dbat_update(uint32_t bat_reg)
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;

if (!gTLBFlushDBatEntries || !gTLBFlushDPatEntries) {
if (!gTLBFlushDBatEntries) {
gTLBFlushDBatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_all_entries<TLBType::DTLB>);
add_ctx_sync_action(&tlb_flush_bat_entries<TLBType::DTLB>);
}
mmu_pat_ctx_changed();
}

void mmu_pat_ctx_changed()
{
// Page address translation context changed so we need to flush
// all PAT entries from both ITLB and DTLB
if (!gTLBFlushIPatEntries || !gTLBFlushDPatEntries) {
gTLBFlushIPatEntries = true;
gTLBFlushDPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::ITLB>);
add_ctx_sync_action(&tlb_flush_pat_entries<TLBType::DTLB>);
// Page address translation context changed so invalidate all PAT entries
// from both ITLB and DTLB.
if (!gTLBInvalidatePatEntries) {
gTLBInvalidatePatEntries = true;
add_ctx_sync_action(&tlb_invalidate_pat_entries);
}
}

Expand DownExpand Up@@ -1150,7 +1183,7 @@ inline T mmu_read_vmem(uint32_t opcode, uint32_t guest_va)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1321,7 +1354,7 @@ inline void mmu_write_vmem(uint32_t opcode, uint32_t guest_va, T value)
bool needs_swap = false;
#endif
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (tlb1_entry->matches_tag(tag)) { // primary TLB hit -> fast path
#ifdef TLB_PROFILING
num_primary_dtlb_hits++;
#endif
Expand DownExpand Up@@ -1895,7 +1928,7 @@ bool mmu_translate_dbg(uint32_t guest_va, uint32_t &guest_pa) {
tlb1_entry = &pCurDTLB1[(guest_va >> PPC_PAGE_SIZE_BITS) & tlb_size_mask];

do {
if (tlb1_entry->tag != tag) {
if (!tlb1_entry->matches_tag(tag)) {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb<TLBType::DTLB>(guest_va, tag);
if (tlb2_entry == nullptr) {
Expand DownExpand Up@@ -1946,12 +1979,15 @@ static void invalidate_tlb_entries(std::array<TLBEntry, N> &tlb) {
tlb_el.host_va_offs_r = 0;
tlb_el.host_va_offs_w = 0;
tlb_el.phys_tag = 0;
tlb_el.reserved = 0;
tlb_el.pat_generation = 0;
}
}

void ppc_mmu_init()
{
gTLBPatGeneration = 0;
gTLBInvalidatePatEntries = false;

last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};

mmu_exception_handler = ppc_exception_handler;
Expand Down
34 changes: 0 additions & 34 deletions cpu/ppc/ppcmmu.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMMU_H
#define PPCMMU_H

#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <functional>

Expand DownExpand Up@@ -84,38 +82,6 @@ typedef struct MapDmaResult {
constexpr uint32_t PPC_PAGE_SIZE_BITS = 12;
constexpr uint32_t PPC_PAGE_SIZE = (1 << PPC_PAGE_SIZE_BITS);
constexpr uint32_t PPC_PAGE_MASK = ~(PPC_PAGE_SIZE - 1);
constexpr uint32_t TLB_SIZE = 4096;
constexpr uint32_t TLB2_WAYS = 4;
constexpr uint32_t TLB_INVALID_TAG = 0xFFFFFFFF;
constexpr uint32_t TLB_VPS_MASK = 0x0FFFF000; // mask for TLB invalidation

typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
struct { // for memory pages
int64_t host_va_offs_r;
int64_t host_va_offs_w;
};
struct { // for MMIO pages
AddressMapEntry* rgn_desc;
int64_t dev_base_va;
};
};
uint32_t phys_tag;
uint32_t reserved;
} TLBEntry;

enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
PAGE_NOPHYS = 1 << 2, // no physical storage for this page (unmapped)
TLBE_FROM_BAT = 1 << 3, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 4, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 5, // page is writable
PTE_SET_C = 1 << 6, // tells if C bit of the PTE needs to be updated
};

extern std::function<void(uint32_t bat_reg)> ibat_update;
extern std::function<void(uint32_t bat_reg)> dbat_update;
Expand Down
1 change: 1 addition & 0 deletions devices/common/dbdma.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/memctrl/memctrlbase.h>

#include <cinttypes>
#include <cstring>
Expand Down
Loading