diff options
Diffstat (limited to 'src/tests')
| -rw-r--r-- | src/tests/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/tests/common/bit_field.cpp | 90 | ||||
| -rw-r--r-- | src/tests/common/bit_utils.cpp | 23 | ||||
| -rw-r--r-- | src/tests/common/multi_level_queue.cpp | 55 | ||||
| -rw-r--r-- | src/tests/core/arm/arm_test_common.cpp | 11 | ||||
| -rw-r--r-- | src/tests/core/arm/arm_test_common.h | 8 | ||||
| -rw-r--r-- | src/tests/core/core_timing.cpp | 220 |
7 files changed, 296 insertions, 114 deletions
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 37f09ce5f..c7038b217 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt | |||
| @@ -1,4 +1,7 @@ | |||
| 1 | add_executable(tests | 1 | add_executable(tests |
| 2 | common/bit_field.cpp | ||
| 3 | common/bit_utils.cpp | ||
| 4 | common/multi_level_queue.cpp | ||
| 2 | common/param_package.cpp | 5 | common/param_package.cpp |
| 3 | common/ring_buffer.cpp | 6 | common/ring_buffer.cpp |
| 4 | core/arm/arm_test_common.cpp | 7 | core/arm/arm_test_common.cpp |
diff --git a/src/tests/common/bit_field.cpp b/src/tests/common/bit_field.cpp new file mode 100644 index 000000000..8ca1889f9 --- /dev/null +++ b/src/tests/common/bit_field.cpp | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | // Copyright 2019 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <cstring> | ||
| 7 | #include <type_traits> | ||
| 8 | #include <catch2/catch.hpp> | ||
| 9 | #include "common/bit_field.h" | ||
| 10 | |||
| 11 | TEST_CASE("BitField", "[common]") { | ||
| 12 | enum class TestEnum : u32 { | ||
| 13 | A = 0b10111101, | ||
| 14 | B = 0b10101110, | ||
| 15 | C = 0b00001111, | ||
| 16 | }; | ||
| 17 | |||
| 18 | union LEBitField { | ||
| 19 | u32_le raw; | ||
| 20 | BitField<0, 6, u32> a; | ||
| 21 | BitField<6, 4, s32> b; | ||
| 22 | BitField<10, 8, TestEnum> c; | ||
| 23 | BitField<18, 14, u32> d; | ||
| 24 | } le_bitfield; | ||
| 25 | |||
| 26 | union BEBitField { | ||
| 27 | u32_be raw; | ||
| 28 | BitFieldBE<0, 6, u32> a; | ||
| 29 | BitFieldBE<6, 4, s32> b; | ||
| 30 | BitFieldBE<10, 8, TestEnum> c; | ||
| 31 | BitFieldBE<18, 14, u32> d; | ||
| 32 | } be_bitfield; | ||
| 33 | |||
| 34 | static_assert(sizeof(LEBitField) == sizeof(u32)); | ||
| 35 | static_assert(sizeof(BEBitField) == sizeof(u32)); | ||
| 36 | static_assert(std::is_trivially_copyable_v<LEBitField>); | ||
| 37 | static_assert(std::is_trivially_copyable_v<BEBitField>); | ||
| 38 | |||
| 39 | std::array<u8, 4> raw{{ | ||
| 40 | 0b01101100, | ||
| 41 | 0b11110110, | ||
| 42 | 0b10111010, | ||
| 43 | 0b11101100, | ||
| 44 | }}; | ||
| 45 | |||
| 46 | std::memcpy(&le_bitfield, &raw, sizeof(raw)); | ||
| 47 | std::memcpy(&be_bitfield, &raw, sizeof(raw)); | ||
| 48 | |||
| 49 | // bit fields: 11101100101110'10111101'1001'101100 | ||
| 50 | REQUIRE(le_bitfield.raw == 0b11101100'10111010'11110110'01101100); | ||
| 51 | REQUIRE(le_bitfield.a == 0b101100); | ||
| 52 | REQUIRE(le_bitfield.b == -7); // 1001 as two's complement | ||
| 53 | REQUIRE(le_bitfield.c == TestEnum::A); | ||
| 54 | REQUIRE(le_bitfield.d == 0b11101100101110); | ||
| 55 | |||
| 56 | le_bitfield.a.Assign(0b000111); | ||
| 57 | le_bitfield.b.Assign(-1); | ||
| 58 | le_bitfield.c.Assign(TestEnum::C); | ||
| 59 | le_bitfield.d.Assign(0b01010101010101); | ||
| 60 | std::memcpy(&raw, &le_bitfield, sizeof(raw)); | ||
| 61 | // bit fields: 01010101010101'00001111'1111'000111 | ||
| 62 | REQUIRE(le_bitfield.raw == 0b01010101'01010100'00111111'11000111); | ||
| 63 | REQUIRE(raw == std::array<u8, 4>{{ | ||
| 64 | 0b11000111, | ||
| 65 | 0b00111111, | ||
| 66 | 0b01010100, | ||
| 67 | 0b01010101, | ||
| 68 | }}); | ||
| 69 | |||
| 70 | // bit fields: 01101100111101'10101110'1011'101100 | ||
| 71 | REQUIRE(be_bitfield.raw == 0b01101100'11110110'10111010'11101100); | ||
| 72 | REQUIRE(be_bitfield.a == 0b101100); | ||
| 73 | REQUIRE(be_bitfield.b == -5); // 1011 as two's complement | ||
| 74 | REQUIRE(be_bitfield.c == TestEnum::B); | ||
| 75 | REQUIRE(be_bitfield.d == 0b01101100111101); | ||
| 76 | |||
| 77 | be_bitfield.a.Assign(0b000111); | ||
| 78 | be_bitfield.b.Assign(-1); | ||
| 79 | be_bitfield.c.Assign(TestEnum::C); | ||
| 80 | be_bitfield.d.Assign(0b01010101010101); | ||
| 81 | std::memcpy(&raw, &be_bitfield, sizeof(raw)); | ||
| 82 | // bit fields: 01010101010101'00001111'1111'000111 | ||
| 83 | REQUIRE(be_bitfield.raw == 0b01010101'01010100'00111111'11000111); | ||
| 84 | REQUIRE(raw == std::array<u8, 4>{{ | ||
| 85 | 0b01010101, | ||
| 86 | 0b01010100, | ||
| 87 | 0b00111111, | ||
| 88 | 0b11000111, | ||
| 89 | }}); | ||
| 90 | } | ||
diff --git a/src/tests/common/bit_utils.cpp b/src/tests/common/bit_utils.cpp new file mode 100644 index 000000000..479b5995a --- /dev/null +++ b/src/tests/common/bit_utils.cpp | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <catch2/catch.hpp> | ||
| 6 | #include <math.h> | ||
| 7 | #include "common/bit_util.h" | ||
| 8 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | TEST_CASE("BitUtils::CountTrailingZeroes", "[common]") { | ||
| 12 | REQUIRE(Common::CountTrailingZeroes32(0) == 32); | ||
| 13 | REQUIRE(Common::CountTrailingZeroes64(0) == 64); | ||
| 14 | REQUIRE(Common::CountTrailingZeroes32(9) == 0); | ||
| 15 | REQUIRE(Common::CountTrailingZeroes32(8) == 3); | ||
| 16 | REQUIRE(Common::CountTrailingZeroes32(0x801000) == 12); | ||
| 17 | REQUIRE(Common::CountTrailingZeroes64(9) == 0); | ||
| 18 | REQUIRE(Common::CountTrailingZeroes64(8) == 3); | ||
| 19 | REQUIRE(Common::CountTrailingZeroes64(0x801000) == 12); | ||
| 20 | REQUIRE(Common::CountTrailingZeroes64(0x801000000000UL) == 36); | ||
| 21 | } | ||
| 22 | |||
| 23 | } // namespace Common | ||
diff --git a/src/tests/common/multi_level_queue.cpp b/src/tests/common/multi_level_queue.cpp new file mode 100644 index 000000000..cca7ec7da --- /dev/null +++ b/src/tests/common/multi_level_queue.cpp | |||
| @@ -0,0 +1,55 @@ | |||
| 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 <catch2/catch.hpp> | ||
| 6 | #include <math.h> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/multi_level_queue.h" | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | TEST_CASE("MultiLevelQueue", "[common]") { | ||
| 13 | std::array<f32, 8> values = {0.0, 5.0, 1.0, 9.0, 8.0, 2.0, 6.0, 7.0}; | ||
| 14 | Common::MultiLevelQueue<f32, 64> mlq; | ||
| 15 | REQUIRE(mlq.empty()); | ||
| 16 | mlq.add(values[2], 2); | ||
| 17 | mlq.add(values[7], 7); | ||
| 18 | mlq.add(values[3], 3); | ||
| 19 | mlq.add(values[4], 4); | ||
| 20 | mlq.add(values[0], 0); | ||
| 21 | mlq.add(values[5], 5); | ||
| 22 | mlq.add(values[6], 6); | ||
| 23 | mlq.add(values[1], 1); | ||
| 24 | u32 index = 0; | ||
| 25 | bool all_set = true; | ||
| 26 | for (auto& f : mlq) { | ||
| 27 | all_set &= (f == values[index]); | ||
| 28 | index++; | ||
| 29 | } | ||
| 30 | REQUIRE(all_set); | ||
| 31 | REQUIRE(!mlq.empty()); | ||
| 32 | f32 v = 8.0; | ||
| 33 | mlq.add(v, 2); | ||
| 34 | v = -7.0; | ||
| 35 | mlq.add(v, 2, false); | ||
| 36 | REQUIRE(mlq.front(2) == -7.0); | ||
| 37 | mlq.yield(2); | ||
| 38 | REQUIRE(mlq.front(2) == values[2]); | ||
| 39 | REQUIRE(mlq.back(2) == -7.0); | ||
| 40 | REQUIRE(mlq.empty(8)); | ||
| 41 | v = 10.0; | ||
| 42 | mlq.add(v, 8); | ||
| 43 | mlq.adjust(v, 8, 9); | ||
| 44 | REQUIRE(mlq.front(9) == v); | ||
| 45 | REQUIRE(mlq.empty(8)); | ||
| 46 | REQUIRE(!mlq.empty(9)); | ||
| 47 | mlq.adjust(values[0], 0, 9); | ||
| 48 | REQUIRE(mlq.highest_priority_set() == 1); | ||
| 49 | REQUIRE(mlq.lowest_priority_set() == 9); | ||
| 50 | mlq.remove(values[1], 1); | ||
| 51 | REQUIRE(mlq.highest_priority_set() == 2); | ||
| 52 | REQUIRE(mlq.empty(1)); | ||
| 53 | } | ||
| 54 | |||
| 55 | } // namespace Common | ||
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index 9b8a44fa1..3e1a735c3 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | 6 | ||
| 7 | #include "common/page_table.h" | ||
| 7 | #include "core/core.h" | 8 | #include "core/core.h" |
| 8 | #include "core/hle/kernel/process.h" | 9 | #include "core/hle/kernel/process.h" |
| 9 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| @@ -13,16 +14,16 @@ | |||
| 13 | namespace ArmTests { | 14 | namespace ArmTests { |
| 14 | 15 | ||
| 15 | TestEnvironment::TestEnvironment(bool mutable_memory_) | 16 | TestEnvironment::TestEnvironment(bool mutable_memory_) |
| 16 | : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { | 17 | : mutable_memory(mutable_memory_), |
| 17 | 18 | test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} { | |
| 18 | auto process = Kernel::Process::Create(kernel, ""); | 19 | auto process = Kernel::Process::Create(Core::System::GetInstance(), ""); |
| 19 | kernel.MakeCurrentProcess(process.get()); | 20 | kernel.MakeCurrentProcess(process.get()); |
| 20 | page_table = &Core::CurrentProcess()->VMManager().page_table; | 21 | page_table = &process->VMManager().page_table; |
| 21 | 22 | ||
| 22 | std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); | 23 | std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); |
| 23 | page_table->special_regions.clear(); | 24 | page_table->special_regions.clear(); |
| 24 | std::fill(page_table->attributes.begin(), page_table->attributes.end(), | 25 | std::fill(page_table->attributes.begin(), page_table->attributes.end(), |
| 25 | Memory::PageType::Unmapped); | 26 | Common::PageType::Unmapped); |
| 26 | 27 | ||
| 27 | Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); | 28 | Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); |
| 28 | Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); | 29 | Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); |
diff --git a/src/tests/core/arm/arm_test_common.h b/src/tests/core/arm/arm_test_common.h index 0b7539601..d145dbfcc 100644 --- a/src/tests/core/arm/arm_test_common.h +++ b/src/tests/core/arm/arm_test_common.h | |||
| @@ -9,10 +9,10 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "common/memory_hook.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/memory_hook.h" | ||
| 14 | 14 | ||
| 15 | namespace Memory { | 15 | namespace Common { |
| 16 | struct PageTable; | 16 | struct PageTable; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| @@ -58,7 +58,7 @@ public: | |||
| 58 | 58 | ||
| 59 | private: | 59 | private: |
| 60 | friend struct TestMemory; | 60 | friend struct TestMemory; |
| 61 | struct TestMemory final : Memory::MemoryHook { | 61 | struct TestMemory final : Common::MemoryHook { |
| 62 | explicit TestMemory(TestEnvironment* env_) : env(env_) {} | 62 | explicit TestMemory(TestEnvironment* env_) : env(env_) {} |
| 63 | TestEnvironment* env; | 63 | TestEnvironment* env; |
| 64 | 64 | ||
| @@ -86,7 +86,7 @@ private: | |||
| 86 | bool mutable_memory; | 86 | bool mutable_memory; |
| 87 | std::shared_ptr<TestMemory> test_memory; | 87 | std::shared_ptr<TestMemory> test_memory; |
| 88 | std::vector<WriteRecord> write_records; | 88 | std::vector<WriteRecord> write_records; |
| 89 | Memory::PageTable* page_table = nullptr; | 89 | Common::PageTable* page_table = nullptr; |
| 90 | Kernel::KernelCore kernel; | 90 | Kernel::KernelCore kernel; |
| 91 | }; | 91 | }; |
| 92 | 92 | ||
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index 2242c14cf..340d6a272 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp | |||
| @@ -28,100 +28,103 @@ void CallbackTemplate(u64 userdata, s64 cycles_late) { | |||
| 28 | REQUIRE(lateness == cycles_late); | 28 | REQUIRE(lateness == cycles_late); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | class ScopeInit final { | 31 | struct ScopeInit final { |
| 32 | public: | ||
| 33 | ScopeInit() { | 32 | ScopeInit() { |
| 34 | CoreTiming::Init(); | 33 | core_timing.Initialize(); |
| 35 | } | 34 | } |
| 36 | ~ScopeInit() { | 35 | ~ScopeInit() { |
| 37 | CoreTiming::Shutdown(); | 36 | core_timing.Shutdown(); |
| 38 | } | 37 | } |
| 38 | |||
| 39 | Core::Timing::CoreTiming core_timing; | ||
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| 41 | static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0, | 42 | static void AdvanceAndCheck(Core::Timing::CoreTiming& core_timing, u32 idx, int downcount, |
| 42 | int cpu_downcount = 0) { | 43 | int expected_lateness = 0, int cpu_downcount = 0) { |
| 43 | callbacks_ran_flags = 0; | 44 | callbacks_ran_flags = 0; |
| 44 | expected_callback = CB_IDS[idx]; | 45 | expected_callback = CB_IDS[idx]; |
| 45 | lateness = expected_lateness; | 46 | lateness = expected_lateness; |
| 46 | 47 | ||
| 47 | CoreTiming::AddTicks(CoreTiming::GetDowncount() - | 48 | // Pretend we executed X cycles of instructions. |
| 48 | cpu_downcount); // Pretend we executed X cycles of instructions. | 49 | core_timing.AddTicks(core_timing.GetDowncount() - cpu_downcount); |
| 49 | CoreTiming::Advance(); | 50 | core_timing.Advance(); |
| 50 | 51 | ||
| 51 | REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags); | 52 | REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags); |
| 52 | REQUIRE(downcount == CoreTiming::GetDowncount()); | 53 | REQUIRE(downcount == core_timing.GetDowncount()); |
| 53 | } | 54 | } |
| 54 | 55 | ||
| 55 | TEST_CASE("CoreTiming[BasicOrder]", "[core]") { | 56 | TEST_CASE("CoreTiming[BasicOrder]", "[core]") { |
| 56 | ScopeInit guard; | 57 | ScopeInit guard; |
| 58 | auto& core_timing = guard.core_timing; | ||
| 57 | 59 | ||
| 58 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); | 60 | Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); |
| 59 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); | 61 | Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); |
| 60 | CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); | 62 | Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>); |
| 61 | CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>); | 63 | Core::Timing::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>); |
| 62 | CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>); | 64 | Core::Timing::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>); |
| 63 | 65 | ||
| 64 | // Enter slice 0 | 66 | // Enter slice 0 |
| 65 | CoreTiming::Advance(); | 67 | core_timing.Advance(); |
| 66 | 68 | ||
| 67 | // D -> B -> C -> A -> E | 69 | // D -> B -> C -> A -> E |
| 68 | CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]); | 70 | core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]); |
| 69 | REQUIRE(1000 == CoreTiming::GetDowncount()); | 71 | REQUIRE(1000 == core_timing.GetDowncount()); |
| 70 | CoreTiming::ScheduleEvent(500, cb_b, CB_IDS[1]); | 72 | core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]); |
| 71 | REQUIRE(500 == CoreTiming::GetDowncount()); | 73 | REQUIRE(500 == core_timing.GetDowncount()); |
| 72 | CoreTiming::ScheduleEvent(800, cb_c, CB_IDS[2]); | 74 | core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]); |
| 73 | REQUIRE(500 == CoreTiming::GetDowncount()); | 75 | REQUIRE(500 == core_timing.GetDowncount()); |
| 74 | CoreTiming::ScheduleEvent(100, cb_d, CB_IDS[3]); | 76 | core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]); |
| 75 | REQUIRE(100 == CoreTiming::GetDowncount()); | 77 | REQUIRE(100 == core_timing.GetDowncount()); |
| 76 | CoreTiming::ScheduleEvent(1200, cb_e, CB_IDS[4]); | 78 | core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]); |
| 77 | REQUIRE(100 == CoreTiming::GetDowncount()); | 79 | REQUIRE(100 == core_timing.GetDowncount()); |
| 78 | 80 | ||
| 79 | AdvanceAndCheck(3, 400); | 81 | AdvanceAndCheck(core_timing, 3, 400); |
| 80 | AdvanceAndCheck(1, 300); | 82 | AdvanceAndCheck(core_timing, 1, 300); |
| 81 | AdvanceAndCheck(2, 200); | 83 | AdvanceAndCheck(core_timing, 2, 200); |
| 82 | AdvanceAndCheck(0, 200); | 84 | AdvanceAndCheck(core_timing, 0, 200); |
| 83 | AdvanceAndCheck(4, MAX_SLICE_LENGTH); | 85 | AdvanceAndCheck(core_timing, 4, MAX_SLICE_LENGTH); |
| 84 | } | 86 | } |
| 85 | 87 | ||
| 86 | TEST_CASE("CoreTiming[Threadsave]", "[core]") { | 88 | TEST_CASE("CoreTiming[Threadsave]", "[core]") { |
| 87 | ScopeInit guard; | 89 | ScopeInit guard; |
| 90 | auto& core_timing = guard.core_timing; | ||
| 88 | 91 | ||
| 89 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); | 92 | Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); |
| 90 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); | 93 | Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); |
| 91 | CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); | 94 | Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>); |
| 92 | CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>); | 95 | Core::Timing::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>); |
| 93 | CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>); | 96 | Core::Timing::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>); |
| 94 | 97 | ||
| 95 | // Enter slice 0 | 98 | // Enter slice 0 |
| 96 | CoreTiming::Advance(); | 99 | core_timing.Advance(); |
| 97 | 100 | ||
| 98 | // D -> B -> C -> A -> E | 101 | // D -> B -> C -> A -> E |
| 99 | CoreTiming::ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]); | 102 | core_timing.ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]); |
| 100 | // Manually force since ScheduleEventThreadsafe doesn't call it | 103 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 101 | CoreTiming::ForceExceptionCheck(1000); | 104 | core_timing.ForceExceptionCheck(1000); |
| 102 | REQUIRE(1000 == CoreTiming::GetDowncount()); | 105 | REQUIRE(1000 == core_timing.GetDowncount()); |
| 103 | CoreTiming::ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]); | 106 | core_timing.ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]); |
| 104 | // Manually force since ScheduleEventThreadsafe doesn't call it | 107 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 105 | CoreTiming::ForceExceptionCheck(500); | 108 | core_timing.ForceExceptionCheck(500); |
| 106 | REQUIRE(500 == CoreTiming::GetDowncount()); | 109 | REQUIRE(500 == core_timing.GetDowncount()); |
| 107 | CoreTiming::ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]); | 110 | core_timing.ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]); |
| 108 | // Manually force since ScheduleEventThreadsafe doesn't call it | 111 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 109 | CoreTiming::ForceExceptionCheck(800); | 112 | core_timing.ForceExceptionCheck(800); |
| 110 | REQUIRE(500 == CoreTiming::GetDowncount()); | 113 | REQUIRE(500 == core_timing.GetDowncount()); |
| 111 | CoreTiming::ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]); | 114 | core_timing.ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]); |
| 112 | // Manually force since ScheduleEventThreadsafe doesn't call it | 115 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 113 | CoreTiming::ForceExceptionCheck(100); | 116 | core_timing.ForceExceptionCheck(100); |
| 114 | REQUIRE(100 == CoreTiming::GetDowncount()); | 117 | REQUIRE(100 == core_timing.GetDowncount()); |
| 115 | CoreTiming::ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]); | 118 | core_timing.ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]); |
| 116 | // Manually force since ScheduleEventThreadsafe doesn't call it | 119 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 117 | CoreTiming::ForceExceptionCheck(1200); | 120 | core_timing.ForceExceptionCheck(1200); |
| 118 | REQUIRE(100 == CoreTiming::GetDowncount()); | 121 | REQUIRE(100 == core_timing.GetDowncount()); |
| 119 | 122 | ||
| 120 | AdvanceAndCheck(3, 400); | 123 | AdvanceAndCheck(core_timing, 3, 400); |
| 121 | AdvanceAndCheck(1, 300); | 124 | AdvanceAndCheck(core_timing, 1, 300); |
| 122 | AdvanceAndCheck(2, 200); | 125 | AdvanceAndCheck(core_timing, 2, 200); |
| 123 | AdvanceAndCheck(0, 200); | 126 | AdvanceAndCheck(core_timing, 0, 200); |
| 124 | AdvanceAndCheck(4, MAX_SLICE_LENGTH); | 127 | AdvanceAndCheck(core_timing, 4, MAX_SLICE_LENGTH); |
| 125 | } | 128 | } |
| 126 | 129 | ||
| 127 | namespace SharedSlotTest { | 130 | namespace SharedSlotTest { |
| @@ -142,59 +145,63 @@ TEST_CASE("CoreTiming[SharedSlot]", "[core]") { | |||
| 142 | using namespace SharedSlotTest; | 145 | using namespace SharedSlotTest; |
| 143 | 146 | ||
| 144 | ScopeInit guard; | 147 | ScopeInit guard; |
| 148 | auto& core_timing = guard.core_timing; | ||
| 145 | 149 | ||
| 146 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", FifoCallback<0>); | 150 | Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", FifoCallback<0>); |
| 147 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", FifoCallback<1>); | 151 | Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", FifoCallback<1>); |
| 148 | CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", FifoCallback<2>); | 152 | Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", FifoCallback<2>); |
| 149 | CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", FifoCallback<3>); | 153 | Core::Timing::EventType* cb_d = core_timing.RegisterEvent("callbackD", FifoCallback<3>); |
| 150 | CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", FifoCallback<4>); | 154 | Core::Timing::EventType* cb_e = core_timing.RegisterEvent("callbackE", FifoCallback<4>); |
| 151 | 155 | ||
| 152 | CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]); | 156 | core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]); |
| 153 | CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]); | 157 | core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]); |
| 154 | CoreTiming::ScheduleEvent(1000, cb_c, CB_IDS[2]); | 158 | core_timing.ScheduleEvent(1000, cb_c, CB_IDS[2]); |
| 155 | CoreTiming::ScheduleEvent(1000, cb_d, CB_IDS[3]); | 159 | core_timing.ScheduleEvent(1000, cb_d, CB_IDS[3]); |
| 156 | CoreTiming::ScheduleEvent(1000, cb_e, CB_IDS[4]); | 160 | core_timing.ScheduleEvent(1000, cb_e, CB_IDS[4]); |
| 157 | 161 | ||
| 158 | // Enter slice 0 | 162 | // Enter slice 0 |
| 159 | CoreTiming::Advance(); | 163 | core_timing.Advance(); |
| 160 | REQUIRE(1000 == CoreTiming::GetDowncount()); | 164 | REQUIRE(1000 == core_timing.GetDowncount()); |
| 161 | 165 | ||
| 162 | callbacks_ran_flags = 0; | 166 | callbacks_ran_flags = 0; |
| 163 | counter = 0; | 167 | counter = 0; |
| 164 | lateness = 0; | 168 | lateness = 0; |
| 165 | CoreTiming::AddTicks(CoreTiming::GetDowncount()); | 169 | core_timing.AddTicks(core_timing.GetDowncount()); |
| 166 | CoreTiming::Advance(); | 170 | core_timing.Advance(); |
| 167 | REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount()); | 171 | REQUIRE(MAX_SLICE_LENGTH == core_timing.GetDowncount()); |
| 168 | REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong()); | 172 | REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong()); |
| 169 | } | 173 | } |
| 170 | 174 | ||
| 171 | TEST_CASE("CoreTiming[PredictableLateness]", "[core]") { | 175 | TEST_CASE("Core::Timing[PredictableLateness]", "[core]") { |
| 172 | ScopeInit guard; | 176 | ScopeInit guard; |
| 177 | auto& core_timing = guard.core_timing; | ||
| 173 | 178 | ||
| 174 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); | 179 | Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); |
| 175 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); | 180 | Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); |
| 176 | 181 | ||
| 177 | // Enter slice 0 | 182 | // Enter slice 0 |
| 178 | CoreTiming::Advance(); | 183 | core_timing.Advance(); |
| 179 | 184 | ||
| 180 | CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]); | 185 | core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]); |
| 181 | CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]); | 186 | core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]); |
| 182 | 187 | ||
| 183 | AdvanceAndCheck(0, 90, 10, -10); // (100 - 10) | 188 | AdvanceAndCheck(core_timing, 0, 90, 10, -10); // (100 - 10) |
| 184 | AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50); | 189 | AdvanceAndCheck(core_timing, 1, MAX_SLICE_LENGTH, 50, -50); |
| 185 | } | 190 | } |
| 186 | 191 | ||
| 187 | namespace ChainSchedulingTest { | 192 | namespace ChainSchedulingTest { |
| 188 | static int reschedules = 0; | 193 | static int reschedules = 0; |
| 189 | 194 | ||
| 190 | static void RescheduleCallback(u64 userdata, s64 cycles_late) { | 195 | static void RescheduleCallback(Core::Timing::CoreTiming& core_timing, u64 userdata, |
| 196 | s64 cycles_late) { | ||
| 191 | --reschedules; | 197 | --reschedules; |
| 192 | REQUIRE(reschedules >= 0); | 198 | REQUIRE(reschedules >= 0); |
| 193 | REQUIRE(lateness == cycles_late); | 199 | REQUIRE(lateness == cycles_late); |
| 194 | 200 | ||
| 195 | if (reschedules > 0) | 201 | if (reschedules > 0) { |
| 196 | CoreTiming::ScheduleEvent(1000, reinterpret_cast<CoreTiming::EventType*>(userdata), | 202 | core_timing.ScheduleEvent(1000, reinterpret_cast<Core::Timing::EventType*>(userdata), |
| 197 | userdata); | 203 | userdata); |
| 204 | } | ||
| 198 | } | 205 | } |
| 199 | } // namespace ChainSchedulingTest | 206 | } // namespace ChainSchedulingTest |
| 200 | 207 | ||
| @@ -202,36 +209,39 @@ TEST_CASE("CoreTiming[ChainScheduling]", "[core]") { | |||
| 202 | using namespace ChainSchedulingTest; | 209 | using namespace ChainSchedulingTest; |
| 203 | 210 | ||
| 204 | ScopeInit guard; | 211 | ScopeInit guard; |
| 212 | auto& core_timing = guard.core_timing; | ||
| 205 | 213 | ||
| 206 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); | 214 | Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); |
| 207 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); | 215 | Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); |
| 208 | CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); | 216 | Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>); |
| 209 | CoreTiming::EventType* cb_rs = | 217 | Core::Timing::EventType* cb_rs = core_timing.RegisterEvent( |
| 210 | CoreTiming::RegisterEvent("callbackReschedule", RescheduleCallback); | 218 | "callbackReschedule", [&core_timing](u64 userdata, s64 cycles_late) { |
| 219 | RescheduleCallback(core_timing, userdata, cycles_late); | ||
| 220 | }); | ||
| 211 | 221 | ||
| 212 | // Enter slice 0 | 222 | // Enter slice 0 |
| 213 | CoreTiming::Advance(); | 223 | core_timing.Advance(); |
| 214 | 224 | ||
| 215 | CoreTiming::ScheduleEvent(800, cb_a, CB_IDS[0]); | 225 | core_timing.ScheduleEvent(800, cb_a, CB_IDS[0]); |
| 216 | CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]); | 226 | core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]); |
| 217 | CoreTiming::ScheduleEvent(2200, cb_c, CB_IDS[2]); | 227 | core_timing.ScheduleEvent(2200, cb_c, CB_IDS[2]); |
| 218 | CoreTiming::ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs)); | 228 | core_timing.ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs)); |
| 219 | REQUIRE(800 == CoreTiming::GetDowncount()); | 229 | REQUIRE(800 == core_timing.GetDowncount()); |
| 220 | 230 | ||
| 221 | reschedules = 3; | 231 | reschedules = 3; |
| 222 | AdvanceAndCheck(0, 200); // cb_a | 232 | AdvanceAndCheck(core_timing, 0, 200); // cb_a |
| 223 | AdvanceAndCheck(1, 1000); // cb_b, cb_rs | 233 | AdvanceAndCheck(core_timing, 1, 1000); // cb_b, cb_rs |
| 224 | REQUIRE(2 == reschedules); | 234 | REQUIRE(2 == reschedules); |
| 225 | 235 | ||
| 226 | CoreTiming::AddTicks(CoreTiming::GetDowncount()); | 236 | core_timing.AddTicks(core_timing.GetDowncount()); |
| 227 | CoreTiming::Advance(); // cb_rs | 237 | core_timing.Advance(); // cb_rs |
| 228 | REQUIRE(1 == reschedules); | 238 | REQUIRE(1 == reschedules); |
| 229 | REQUIRE(200 == CoreTiming::GetDowncount()); | 239 | REQUIRE(200 == core_timing.GetDowncount()); |
| 230 | 240 | ||
| 231 | AdvanceAndCheck(2, 800); // cb_c | 241 | AdvanceAndCheck(core_timing, 2, 800); // cb_c |
| 232 | 242 | ||
| 233 | CoreTiming::AddTicks(CoreTiming::GetDowncount()); | 243 | core_timing.AddTicks(core_timing.GetDowncount()); |
| 234 | CoreTiming::Advance(); // cb_rs | 244 | core_timing.Advance(); // cb_rs |
| 235 | REQUIRE(0 == reschedules); | 245 | REQUIRE(0 == reschedules); |
| 236 | REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount()); | 246 | REQUIRE(MAX_SLICE_LENGTH == core_timing.GetDowncount()); |
| 237 | } | 247 | } |