mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-11 20:29:46 +00:00
ppcmmu: add MMU profiling (disabled by default).
This commit is contained in:
parent
bc59bf7c43
commit
085877a8bf
@ -25,7 +25,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
- implement TLB
|
- implement TLB
|
||||||
- implement 601-style BATs
|
- implement 601-style BATs
|
||||||
- add proper error and exception handling
|
- add proper error and exception handling
|
||||||
- clarify what to do in the case of unaligned memory accesses
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ppcmmu.h"
|
#include "ppcmmu.h"
|
||||||
@ -47,6 +46,95 @@ void (*mmu_exception_handler)(Except_Type exception_type, uint32_t srr1_bits);
|
|||||||
PPC_BAT_entry ibat_array[4] = {{0}};
|
PPC_BAT_entry ibat_array[4] = {{0}};
|
||||||
PPC_BAT_entry dbat_array[4] = {{0}};
|
PPC_BAT_entry dbat_array[4] = {{0}};
|
||||||
|
|
||||||
|
//#define MMU_PROFILING // enable MMU profiling
|
||||||
|
|
||||||
|
/* MMU profiling */
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
|
||||||
|
/* global variables for lightweight MMU profiling */
|
||||||
|
uint32_t dmem_reads_total = 0; // counts reads from data memory
|
||||||
|
uint32_t iomem_reads_total = 0; // counts I/O memory reads
|
||||||
|
uint32_t dmem_writes_total = 0; // counts writes to data memory
|
||||||
|
uint32_t iomem_writes_total = 0; // counts I/O memory writes
|
||||||
|
uint32_t exec_reads_total = 0; // counts reads from executable memory
|
||||||
|
uint32_t bat_transl_total = 0; // counts BAT translations
|
||||||
|
uint32_t ptab_transl_total = 0; // counts page table translations
|
||||||
|
uint32_t unaligned_reads = 0; // counts unaligned reads
|
||||||
|
uint32_t unaligned_writes = 0; // counts unaligned writes
|
||||||
|
uint32_t unaligned_crossp_r = 0; // counts unaligned crosspage reads
|
||||||
|
uint32_t unaligned_crossp_w = 0; // counts unaligned crosspage writes
|
||||||
|
|
||||||
|
#include "utils/profiler.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class MMUProfile : public BaseProfile {
|
||||||
|
public:
|
||||||
|
MMUProfile() : BaseProfile("PPC_MMU") {};
|
||||||
|
|
||||||
|
void populate_variables(std::vector<ProfileVar>& vars) {
|
||||||
|
vars.clear();
|
||||||
|
|
||||||
|
vars.push_back({.name = "Data Memory Reads Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = dmem_reads_total});
|
||||||
|
|
||||||
|
vars.push_back({.name = "I/O Memory Reads Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = iomem_reads_total});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Data Memory Writes Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = dmem_writes_total});
|
||||||
|
|
||||||
|
vars.push_back({.name = "I/O Memory Writes Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = iomem_writes_total});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Reads from Executable Memory",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = exec_reads_total});
|
||||||
|
|
||||||
|
vars.push_back({.name = "BAT Translations Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = bat_transl_total});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Page Table Translations Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = ptab_transl_total});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Unaligned Reads Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = unaligned_reads});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Unaligned Writes Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = unaligned_writes});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Unaligned Crosspage Reads Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = unaligned_crossp_r});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Unaligned Crosspage Writes Total",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = unaligned_crossp_w});
|
||||||
|
};
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
dmem_reads_total = 0;
|
||||||
|
iomem_reads_total = 0;
|
||||||
|
dmem_writes_total = 0;
|
||||||
|
iomem_writes_total = 0;
|
||||||
|
exec_reads_total = 0;
|
||||||
|
bat_transl_total = 0;
|
||||||
|
ptab_transl_total = 0;
|
||||||
|
unaligned_reads = 0;
|
||||||
|
unaligned_writes = 0;
|
||||||
|
unaligned_crossp_r = 0;
|
||||||
|
unaligned_crossp_w = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/** remember recently used physical memory regions for quicker translation. */
|
/** remember recently used physical memory regions for quicker translation. */
|
||||||
AddressMapEntry last_read_area = {0xFFFFFFFF, 0xFFFFFFFF};
|
AddressMapEntry last_read_area = {0xFFFFFFFF, 0xFFFFFFFF};
|
||||||
AddressMapEntry last_write_area = {0xFFFFFFFF, 0xFFFFFFFF};
|
AddressMapEntry last_write_area = {0xFFFFFFFF, 0xFFFFFFFF};
|
||||||
@ -367,6 +455,10 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la) {
|
|||||||
if ((bat_entry->access & access_bits) && ((la & bat_entry->hi_mask) == bat_entry->bepi)) {
|
if ((bat_entry->access & access_bits) && ((la & bat_entry->hi_mask) == bat_entry->bepi)) {
|
||||||
bat_hit = true;
|
bat_hit = true;
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
bat_transl_total++;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!bat_entry->prot) {
|
if (!bat_entry->prot) {
|
||||||
mmu_exception_handler(Except_Type::EXC_ISI, 0x08000000);
|
mmu_exception_handler(Except_Type::EXC_ISI, 0x08000000);
|
||||||
}
|
}
|
||||||
@ -380,6 +472,10 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la) {
|
|||||||
/* page address translation */
|
/* page address translation */
|
||||||
if (!bat_hit) {
|
if (!bat_hit) {
|
||||||
pa = page_address_translate(la, true, msr_pr, 0);
|
pa = page_address_translate(la, true, msr_pr, 0);
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
ptab_transl_total++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return pa;
|
return pa;
|
||||||
@ -407,6 +503,10 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write) {
|
|||||||
if ((bat_entry->access & access_bits) && ((la & bat_entry->hi_mask) == bat_entry->bepi)) {
|
if ((bat_entry->access & access_bits) && ((la & bat_entry->hi_mask) == bat_entry->bepi)) {
|
||||||
bat_hit = true;
|
bat_hit = true;
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
bat_transl_total++;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!bat_entry->prot || ((bat_entry->prot & 1) && is_write)) {
|
if (!bat_entry->prot || ((bat_entry->prot & 1) && is_write)) {
|
||||||
ppc_state.spr[SPR::DSISR] = 0x08000000 | (is_write << 25);
|
ppc_state.spr[SPR::DSISR] = 0x08000000 | (is_write << 25);
|
||||||
ppc_state.spr[SPR::DAR] = la;
|
ppc_state.spr[SPR::DAR] = la;
|
||||||
@ -422,6 +522,10 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write) {
|
|||||||
/* page address translation */
|
/* page address translation */
|
||||||
if (!bat_hit) {
|
if (!bat_hit) {
|
||||||
pa = page_address_translate(la, false, msr_pr, is_write);
|
pa = page_address_translate(la, false, msr_pr, is_write);
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
ptab_transl_total++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return pa;
|
return pa;
|
||||||
@ -434,8 +538,9 @@ static void mem_write_unaligned(uint32_t addr, uint32_t value, uint32_t size) {
|
|||||||
|
|
||||||
if (((addr & 0xFFF) + size) > 0x1000) {
|
if (((addr & 0xFFF) + size) > 0x1000) {
|
||||||
// Special case: unaligned cross-page writes
|
// Special case: unaligned cross-page writes
|
||||||
LOG_F(WARNING, "Cross-page unaligned write, addr=%08X, size=%d\n",
|
#ifdef MMU_PROFILING
|
||||||
addr, size);
|
unaligned_crossp_w++;
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t phys_addr;
|
uint32_t phys_addr;
|
||||||
uint32_t shift = (size - 1) * 8;
|
uint32_t shift = (size - 1) * 8;
|
||||||
@ -463,6 +568,10 @@ static void mem_write_unaligned(uint32_t addr, uint32_t value, uint32_t size) {
|
|||||||
} else {
|
} else {
|
||||||
write_phys_mem<uint32_t, false>(&last_write_area, addr, value);
|
write_phys_mem<uint32_t, false>(&last_write_area, addr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
unaligned_writes++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,8 +635,9 @@ static uint32_t mem_grab_unaligned(uint32_t addr, uint32_t size) {
|
|||||||
|
|
||||||
if (((addr & 0xFFF) + size) > 0x1000) {
|
if (((addr & 0xFFF) + size) > 0x1000) {
|
||||||
// Special case: misaligned cross-page reads
|
// Special case: misaligned cross-page reads
|
||||||
LOG_F(WARNING, "Cross-page unaligned read, addr=%08X, size=%d\n",
|
#ifdef MMU_PROFILING
|
||||||
addr, size);
|
unaligned_crossp_r++;
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t phys_addr;
|
uint32_t phys_addr;
|
||||||
uint32_t res = 0;
|
uint32_t res = 0;
|
||||||
@ -541,7 +651,8 @@ static uint32_t mem_grab_unaligned(uint32_t addr, uint32_t size) {
|
|||||||
phys_addr = ppc_mmu_addr_translate(addr, 0);
|
phys_addr = ppc_mmu_addr_translate(addr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = (res << 8) | read_phys_mem<uint8_t, false>(&last_read_area, phys_addr);
|
res = (res << 8) |
|
||||||
|
read_phys_mem<uint8_t, false>(&last_read_area, phys_addr);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
@ -556,6 +667,10 @@ static uint32_t mem_grab_unaligned(uint32_t addr, uint32_t size) {
|
|||||||
} else {
|
} else {
|
||||||
return read_phys_mem<uint32_t, false>(&last_read_area, addr);
|
return read_phys_mem<uint32_t, false>(&last_read_area, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
unaligned_reads++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -614,6 +729,10 @@ uint64_t mem_grab_qword(uint32_t addr) {
|
|||||||
uint8_t* quickinstruction_translate(uint32_t addr) {
|
uint8_t* quickinstruction_translate(uint32_t addr) {
|
||||||
uint8_t* real_addr;
|
uint8_t* real_addr;
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
exec_reads_total++;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* perform instruction address translation if enabled */
|
/* perform instruction address translation if enabled */
|
||||||
if (ppc_state.msr & 0x20) {
|
if (ppc_state.msr & 0x20) {
|
||||||
addr = ppc_mmu_instr_translate(addr);
|
addr = ppc_mmu_instr_translate(addr);
|
||||||
@ -685,4 +804,9 @@ uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size) {
|
|||||||
|
|
||||||
void ppc_mmu_init() {
|
void ppc_mmu_init() {
|
||||||
mmu_exception_handler = ppc_exception_handler;
|
mmu_exception_handler = ppc_exception_handler;
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
gProfilerObj->register_profile("PPC_MMU",
|
||||||
|
std::unique_ptr<BaseProfile>(new MMUProfile()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user