summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt6
-rw-r--r--src/common/memory_hook.cpp11
-rw-r--r--src/common/memory_hook.h47
-rw-r--r--src/common/page_table.cpp29
-rw-r--r--src/common/page_table.h80
-rw-r--r--src/common/uint128.cpp41
-rw-r--r--src/common/uint128.h14
7 files changed, 228 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 3d30f0e3e..43ae8a9e7 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -92,10 +92,14 @@ add_library(common STATIC
92 logging/text_formatter.cpp 92 logging/text_formatter.cpp
93 logging/text_formatter.h 93 logging/text_formatter.h
94 math_util.h 94 math_util.h
95 memory_hook.cpp
96 memory_hook.h
95 microprofile.cpp 97 microprofile.cpp
96 microprofile.h 98 microprofile.h
97 microprofileui.h 99 microprofileui.h
98 misc.cpp 100 misc.cpp
101 page_table.cpp
102 page_table.h
99 param_package.cpp 103 param_package.cpp
100 param_package.h 104 param_package.h
101 quaternion.h 105 quaternion.h
@@ -114,6 +118,8 @@ add_library(common STATIC
114 threadsafe_queue.h 118 threadsafe_queue.h
115 timer.cpp 119 timer.cpp
116 timer.h 120 timer.h
121 uint128.cpp
122 uint128.h
117 vector_math.h 123 vector_math.h
118 web_result.h 124 web_result.h
119) 125)
diff --git a/src/common/memory_hook.cpp b/src/common/memory_hook.cpp
new file mode 100644
index 000000000..3986986d6
--- /dev/null
+++ b/src/common/memory_hook.cpp
@@ -0,0 +1,11 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/memory_hook.h"
6
7namespace Common {
8
9MemoryHook::~MemoryHook() = default;
10
11} // namespace Common
diff --git a/src/common/memory_hook.h b/src/common/memory_hook.h
new file mode 100644
index 000000000..adaa4c2c5
--- /dev/null
+++ b/src/common/memory_hook.h
@@ -0,0 +1,47 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <optional>
9
10#include "common/common_types.h"
11
12namespace Common {
13
14/**
15 * Memory hooks have two purposes:
16 * 1. To allow reads and writes to a region of memory to be intercepted. This is used to implement
17 * texture forwarding and memory breakpoints for debugging.
18 * 2. To allow for the implementation of MMIO devices.
19 *
20 * A hook may be mapped to multiple regions of memory.
21 *
22 * If a std::nullopt or false is returned from a function, the read/write request is passed through
23 * to the underlying memory region.
24 */
25class MemoryHook {
26public:
27 virtual ~MemoryHook();
28
29 virtual std::optional<bool> IsValidAddress(VAddr addr) = 0;
30
31 virtual std::optional<u8> Read8(VAddr addr) = 0;
32 virtual std::optional<u16> Read16(VAddr addr) = 0;
33 virtual std::optional<u32> Read32(VAddr addr) = 0;
34 virtual std::optional<u64> Read64(VAddr addr) = 0;
35
36 virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0;
37
38 virtual bool Write8(VAddr addr, u8 data) = 0;
39 virtual bool Write16(VAddr addr, u16 data) = 0;
40 virtual bool Write32(VAddr addr, u32 data) = 0;
41 virtual bool Write64(VAddr addr, u64 data) = 0;
42
43 virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0;
44};
45
46using MemoryHookPointer = std::shared_ptr<MemoryHook>;
47} // namespace Common
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp
new file mode 100644
index 000000000..8eba1c3f1
--- /dev/null
+++ b/src/common/page_table.cpp
@@ -0,0 +1,29 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/page_table.h"
6
7namespace Common {
8
9PageTable::PageTable(std::size_t page_size_in_bits) : page_size_in_bits{page_size_in_bits} {}
10
11PageTable::~PageTable() = default;
12
13void PageTable::Resize(std::size_t address_space_width_in_bits) {
14 const std::size_t num_page_table_entries = 1ULL
15 << (address_space_width_in_bits - page_size_in_bits);
16
17 pointers.resize(num_page_table_entries);
18 attributes.resize(num_page_table_entries);
19
20 // The default is a 39-bit address space, which causes an initial 1GB allocation size. If the
21 // vector size is subsequently decreased (via resize), the vector might not automatically
22 // actually reallocate/resize its underlying allocation, which wastes up to ~800 MB for
23 // 36-bit titles. Call shrink_to_fit to reduce capacity to what's actually in use.
24
25 pointers.shrink_to_fit();
26 attributes.shrink_to_fit();
27}
28
29} // namespace Common
diff --git a/src/common/page_table.h b/src/common/page_table.h
new file mode 100644
index 000000000..8339f2890
--- /dev/null
+++ b/src/common/page_table.h
@@ -0,0 +1,80 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include <boost/icl/interval_map.hpp>
9#include "common/common_types.h"
10#include "common/memory_hook.h"
11
12namespace Common {
13
14enum class PageType : u8 {
15 /// Page is unmapped and should cause an access error.
16 Unmapped,
17 /// Page is mapped to regular memory. This is the only type you can get pointers to.
18 Memory,
19 /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
20 /// invalidation
21 RasterizerCachedMemory,
22 /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
23 Special,
24};
25
26struct SpecialRegion {
27 enum class Type {
28 DebugHook,
29 IODevice,
30 } type;
31
32 MemoryHookPointer handler;
33
34 bool operator<(const SpecialRegion& other) const {
35 return std::tie(type, handler) < std::tie(other.type, other.handler);
36 }
37
38 bool operator==(const SpecialRegion& other) const {
39 return std::tie(type, handler) == std::tie(other.type, other.handler);
40 }
41};
42
43/**
44 * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely
45 * mimics the way a real CPU page table works.
46 */
47struct PageTable {
48 explicit PageTable(std::size_t page_size_in_bits);
49 ~PageTable();
50
51 /**
52 * Resizes the page table to be able to accomodate enough pages within
53 * a given address space.
54 *
55 * @param address_space_width_in_bits The address size width in bits.
56 */
57 void Resize(std::size_t address_space_width_in_bits);
58
59 /**
60 * Vector of memory pointers backing each page. An entry can only be non-null if the
61 * corresponding entry in the `attributes` vector is of type `Memory`.
62 */
63 std::vector<u8*> pointers;
64
65 /**
66 * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is
67 * of type `Special`.
68 */
69 boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions;
70
71 /**
72 * Vector of fine grained page attributes. If it is set to any value other than `Memory`, then
73 * the corresponding entry in `pointers` MUST be set to null.
74 */
75 std::vector<PageType> attributes;
76
77 const std::size_t page_size_in_bits{};
78};
79
80} // namespace Common
diff --git a/src/common/uint128.cpp b/src/common/uint128.cpp
new file mode 100644
index 000000000..2238a52c5
--- /dev/null
+++ b/src/common/uint128.cpp
@@ -0,0 +1,41 @@
1#ifdef _MSC_VER
2#include <intrin.h>
3
4#pragma intrinsic(_umul128)
5#endif
6#include <cstring>
7#include "common/uint128.h"
8
9namespace Common {
10
11u128 Multiply64Into128(u64 a, u64 b) {
12 u128 result;
13#ifdef _MSC_VER
14 result[0] = _umul128(a, b, &result[1]);
15#else
16 unsigned __int128 tmp = a;
17 tmp *= b;
18 std::memcpy(&result, &tmp, sizeof(u128));
19#endif
20 return result;
21}
22
23std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) {
24 u64 remainder = dividend[0] % divisor;
25 u64 accum = dividend[0] / divisor;
26 if (dividend[1] == 0)
27 return {accum, remainder};
28 // We ignore dividend[1] / divisor as that overflows
29 const u64 first_segment = (dividend[1] % divisor) << 32;
30 accum += (first_segment / divisor) << 32;
31 const u64 second_segment = (first_segment % divisor) << 32;
32 accum += (second_segment / divisor);
33 remainder += second_segment % divisor;
34 if (remainder >= divisor) {
35 accum++;
36 remainder -= divisor;
37 }
38 return {accum, remainder};
39}
40
41} // namespace Common
diff --git a/src/common/uint128.h b/src/common/uint128.h
new file mode 100644
index 000000000..52e6b46eb
--- /dev/null
+++ b/src/common/uint128.h
@@ -0,0 +1,14 @@
1
2#include <utility>
3#include "common/common_types.h"
4
5namespace Common {
6
7// This function multiplies 2 u64 values and produces a u128 value;
8u128 Multiply64Into128(u64 a, u64 b);
9
10// This function divides a u128 by a u32 value and produces two u64 values:
11// the result of division and the remainder
12std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
13
14} // namespace Common