[dynarmic, common] pagetable clustering (#3215)

Raises the size of each page entry to 32 bytes, however, it merges them into a single structure
THEORETICALLY this is better since the access pattern observed corresponds to the program wanting backing_addr/pointers/blocks immediately after one another.
This may improve performance at the cost of some extra memory.
Another implementation would be to structure only backing_addr/blocks within the same virtual buffer.
Alas spamming virtual buffers is evil since each of them is a cache trasher (imagine jumping from wildly different block to wildly different block immediately).

Signed-off-by: lizzie lizzie@eden-emu.dev

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3215
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2026-01-13 00:27:31 +01:00 committed by crueter
parent 1cb8bcf531
commit dceeccd04b
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
13 changed files with 103 additions and 108 deletions

View file

@ -372,6 +372,7 @@ EmitConfig A32AddressSpace::GetEmitConfig() {
.page_table_pointer = std::bit_cast<u64>(conf.page_table),
.page_table_address_space_bits = 32,
.page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits,
.page_table_log2_stride = conf.page_table_log2_stride,
.silently_mirror_page_table = true,
.absolute_offset_page_table = conf.absolute_offset_page_table,
.detect_misaligned_access_via_page_table = conf.detect_misaligned_access_via_page_table,

View file

@ -547,6 +547,7 @@ EmitConfig A64AddressSpace::GetEmitConfig() {
.page_table_pointer = std::bit_cast<u64>(conf.page_table),
.page_table_address_space_bits = conf.page_table_address_space_bits,
.page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits,
.page_table_log2_stride = conf.page_table_log2_stride,
.silently_mirror_page_table = conf.silently_mirror_page_table,
.absolute_offset_page_table = conf.absolute_offset_page_table,
.detect_misaligned_access_via_page_table = conf.detect_misaligned_access_via_page_table,

View file

@ -129,6 +129,7 @@ struct EmitConfig {
u64 page_table_pointer;
size_t page_table_address_space_bits;
int page_table_pointer_mask_bits;
size_t page_table_log2_stride;
bool silently_mirror_page_table;
bool absolute_offset_page_table;
u8 detect_misaligned_access_via_page_table;

View file

@ -268,7 +268,7 @@ std::pair<oaknut::XReg, oaknut::XReg> InlinePageTableEmitVAddrLookup(oaknut::Cod
code.B(NE, *fallback);
}
code.LDR(Xscratch0, Xpagetable, Xscratch0, LSL, 3);
code.LDR(Xscratch0, Xpagetable, Xscratch0, LSL, ctx.conf.page_table_log2_stride);
if (ctx.conf.page_table_pointer_mask_bits != 0) {
const u64 mask = u64(~u64(0)) << ctx.conf.page_table_pointer_mask_bits;

View file

@ -83,9 +83,9 @@ template<>
// TODO: This code assumes vaddr has been zext from 32-bits to 64-bits.
code.mov(tmp, vaddr.cvt32());
code.shr(tmp, static_cast<int>(page_bits));
code.mov(page, qword[r14 + tmp.cvt64() * sizeof(void*)]);
code.shr(tmp, int(page_bits));
code.shl(tmp, int(ctx.conf.page_table_log2_stride));
code.mov(page, qword[r14 + tmp.cvt64()]);
if (ctx.conf.page_table_pointer_mask_bits == 0) {
code.test(page, page);
} else {
@ -138,7 +138,9 @@ template<>
code.test(tmp, u32(-(1 << valid_page_index_bits)));
code.jnz(abort, code.T_NEAR);
}
code.mov(page, qword[r14 + tmp * sizeof(void*)]);
code.shl(tmp, int(ctx.conf.page_table_log2_stride));
code.mov(page, qword[r14 + tmp]);
if (ctx.conf.page_table_pointer_mask_bits == 0) {
code.test(page, page);
} else {

View file

@ -168,6 +168,9 @@ struct UserConfig {
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
std::int32_t page_table_pointer_mask_bits = 0;
// Log2 of the size per page entry, value should be either 3 or 4
std::size_t page_table_log2_stride = 3;
/// Select the architecture version to use.
/// There are minor behavioural differences between versions.
ArchVersion arch_version = ArchVersion::v8;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
@ -179,6 +182,9 @@ struct UserConfig {
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
std::int32_t page_table_pointer_mask_bits = 0;
// Log2 of the size per page entry, value should be either 3 or 4
std::size_t page_table_log2_stride = 3;
/// Counter-timer frequency register. The value of the register is not interpreted by
/// dynarmic.
std::uint32_t cntfrq_el0 = 600000000;