Devirtualize core timing

* Ticking core timing is a very hot path and the components aren't that many so it makes sense to not pay the cost of a virtual call
This commit is contained in:
GPUCode 2024-03-12 00:51:35 +02:00
parent 48d2dd788f
commit e811e340a1
11 changed files with 89 additions and 82 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "externals/mcl"]
path = externals/mcl
url = https://github.com/merryhime/mcl
[submodule "externals/robin-map"]
path = externals/robin-map
url = https://github.com/Tessil/robin-map

1
externals/robin-map vendored Submodule

@ -0,0 +1 @@
Subproject commit f45ebce73b3631fdfb8205e2ba700b726ff0c34f

View File

@ -60,7 +60,7 @@ add_library(teakra
create_target_directory_groups(teakra)
target_link_libraries(teakra PRIVATE Threads::Threads mcl xbyak::xbyak)
target_link_libraries(teakra PRIVATE Threads::Threads tsl::robin_map xbyak::xbyak)
target_include_directories(teakra
PUBLIC ../include
PRIVATE .)

View File

@ -1,13 +1,10 @@
#include <string>
#include <limits>
#include "btdmp.h"
#include "crash.h"
namespace Teakra {
Btdmp::Btdmp(CoreTiming& core_timing) {
core_timing.RegisterCallbacks(this);
}
Btdmp::Btdmp() = default;
Btdmp::~Btdmp() = default;
void Btdmp::Reset() {
@ -21,35 +18,38 @@ void Btdmp::Reset() {
}
void Btdmp::Tick(u64 ticks) {
if (transmit_enable) {
transmit_timer += ticks;
if (transmit_timer >= transmit_period) {
transmit_timer = 0;
std::array<std::int16_t, 2> sample;
for (int i = 0; i < 2; ++i) {
if (transmit_queue.empty()) {
std::printf("BTDMP: transmit buffer underrun\n");
sample[i] = 0;
} else {
sample[i] = static_cast<s16>(transmit_queue.front());
transmit_queue.pop();
transmit_empty = transmit_queue.empty();
transmit_full = false;
if (transmit_empty) {
interrupt_handler();
}
if (!transmit_enable) {
return;
}
transmit_timer += ticks;
while (transmit_timer >= transmit_period) {
transmit_timer -= transmit_period;
std::array<std::int16_t, 2> sample;
for (int i = 0; i < 2; ++i) {
if (transmit_queue.empty()) {
std::printf("BTDMP: transmit buffer underrun\n");
sample[i] = 0;
} else {
sample[i] = static_cast<s16>(transmit_queue.front());
transmit_queue.pop();
transmit_empty = transmit_queue.empty();
transmit_full = false;
if (transmit_empty) {
interrupt_handler();
}
}
if (audio_callback) {
audio_callback(sample);
}
}
if (audio_callback) {
audio_callback(sample);
}
}
}
u64 Btdmp::GetMaxSkip() const {
if (!transmit_enable || transmit_queue.empty()) {
return Infinity;
return std::numeric_limits<u64>::max();
}
u64 ticks = 0;

View File

@ -1,17 +1,17 @@
#pragma once
#include <array>
#include <cstdio>
#include <functional>
#include <utility>
#include <queue>
#include "common_types.h"
#include "core_timing.h"
namespace Teakra {
class Btdmp : public CoreTiming::Callbacks {
class Btdmp {
public:
Btdmp(CoreTiming& core_timing);
Btdmp();
~Btdmp();
void Reset();
@ -68,9 +68,9 @@ public:
return 0;
}
void Tick(u64 ticks) override;
u64 GetMaxSkip() const override;
void Skip(u64 ticks) override;
void Tick(u64 ticks);
u64 GetMaxSkip() const;
void Skip(u64 ticks);
void SetAudioCallback(std::function<void(std::array<std::int16_t, 2>)> callback) {
audio_callback = std::move(callback);

View File

@ -12,6 +12,13 @@ using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;
// Inlining
#ifdef _WIN32
#define FORCE_INLINE __forceinline
#else
#define FORCE_INLINE inline __attribute__((always_inline))
#endif
template <typename T>
constexpr unsigned BitSize() {
return sizeof(T) * 8; // yeah I know I shouldn't use 8 here.

View File

@ -1,46 +1,45 @@
#pragma once
#include <algorithm>
#include <functional>
#include <limits>
#include <vector>
#include <array>
#include "common_types.h"
#include "btdmp.h"
#include "timer.h"
namespace Teakra {
class CoreTiming {
public:
class Callbacks {
public:
virtual ~Callbacks() = default;
virtual void Tick(u64) = 0;
virtual u64 GetMaxSkip() const = 0;
virtual void Skip(u64) = 0;
static constexpr u64 Infinity = std::numeric_limits<u64>::max();
};
CoreTiming(std::array<Timer, 2>& timer_, std::array<Btdmp, 2>& btdmp_) :
timer{timer_}, btdmp{btdmp_} {}
void Tick(u64 ticks = 1) {
for (const auto& callbacks : registered_callbacks) {
callbacks->Tick(ticks);
}
timer[0].Tick(ticks);
timer[1].Tick(ticks);
btdmp[0].Tick(ticks);
btdmp[1].Tick(ticks);
}
u64 Skip(u64 maximum) {
u64 ticks = maximum;
for (const auto& callbacks : registered_callbacks) {
ticks = std::min(ticks, callbacks->GetMaxSkip());
}
for (const auto& callbacks : registered_callbacks) {
callbacks->Skip(ticks);
}
const u64 ticks = GetMaxSkip(maximum);
timer[0].Skip(ticks);
timer[1].Skip(ticks);
btdmp[0].Skip(ticks);
btdmp[1].Skip(ticks);
return ticks;
}
void RegisterCallbacks(Callbacks* callbacks) {
registered_callbacks.push_back(std::move(callbacks));
u64 GetMaxSkip(u64 maximum) {
u64 ticks = maximum;
ticks = std::min(ticks, timer[0].GetMaxSkip());
ticks = std::min(ticks, timer[1].GetMaxSkip());
ticks = std::min(ticks, btdmp[0].GetMaxSkip());
ticks = std::min(ticks, btdmp[1].GetMaxSkip());
return ticks;
}
private:
std::vector<Callbacks*> registered_callbacks;
std::array<Timer, 2>& timer;
std::array<Btdmp, 2>& btdmp;
};
} // namespace Teakra

View File

@ -2,15 +2,14 @@
#include "shared_memory.h"
#include <utility>
#include <atomic>
#include <stdexcept>
#include <tuple>
#include <optional>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <xbyak/xbyak.h>
#include <tsl/robin_map.h>
#include "bit.h"
#include <bit>
#include <set>
#include "core_timing.h"
#include "memory_interface.h"
@ -79,6 +78,12 @@ public:
s32 cycles;
};
enum JitStatus {
Compiling = 0,
EndStaticJump = 1,
EndDynJump = 2,
};
CoreTiming& core_timing;
JitRegisters& regs;
RegisterState* iregs;
@ -91,7 +96,8 @@ public:
std::set<u32> bkrep_end_locations;
std::set<u32> rep_end_locations;
bool compiling = false;
std::unordered_map<size_t, Block, std::identity> code_blocks;
JitStatus status = JitStatus::Compiling;
tsl::robin_map<size_t, Block, std::identity> code_blocks;
const Block* current_blk{};
BlockKey blk_key{};
bool unimplemented = false;
@ -172,7 +178,7 @@ public:
if (new_block) {
// Note: They key may change during compilation, so this needs to be first.
auto& blk = it->second;
auto& blk = it.value();
blk.entry_key = blk_key;
CompileBlock(blk);
}
@ -2523,8 +2529,6 @@ public:
}
void shfc(Ab a, Ab b, Cond cond) {
//NOT_IMPLEMENTED();
//return;
ConditionPass(cond, [&] {
const Reg64 value = rax;
GetAcc(value, a.GetName());

View File

@ -1,6 +1,4 @@
#include <array>
#include <atomic>
#include <cassert>
#include "ahbm.h"
#include "apbp.h"
#include "btdmp.h"
@ -17,15 +15,15 @@
namespace Teakra {
struct Teakra::Impl {
CoreTiming core_timing;
std::array<Timer, 2> timer{};
std::array<Btdmp, 2> btdmp{};
CoreTiming core_timing{timer, btdmp};
SharedMemory shared_memory;
MemoryInterfaceUnit miu;
ICU icu;
Apbp apbp_from_cpu, apbp_from_dsp;
std::array<Timer, 2> timer{{{core_timing}, {core_timing}}};
Ahbm ahbm;
Dma dma{shared_memory, ahbm};
std::array<Btdmp, 2> btdmp{{{core_timing}, {core_timing}}};
MMIORegion mmio{miu, icu, apbp_from_cpu, apbp_from_dsp, timer, dma, ahbm, btdmp};
MemoryInterface memory_interface{shared_memory, miu};
Processor processor;

View File

@ -1,3 +1,4 @@
#include <limits>
#include "crash.h"
#include "timer.h"
#include "crash.h"
@ -75,7 +76,7 @@ void Timer::UpdateMMIO() {
u64 Timer::GetMaxSkip() const {
if (pause || count_mode == CountMode::EventCount)
return Infinity;
return std::numeric_limits<u64>::max();
if (counter == 0) {
if (count_mode == CountMode::AutoRestart) {
@ -83,7 +84,7 @@ u64 Timer::GetMaxSkip() const {
} else if (count_mode == CountMode::FreeRunning) {
return 0xFFFFFFFF;
} else /*Single*/ {
return Infinity;
return std::numeric_limits<u64>::max();
}
}
@ -113,8 +114,4 @@ void Timer::Skip(u64 ticks) {
UpdateMMIO();
}
Timer::Timer(CoreTiming& core_timing) {
core_timing.RegisterCallbacks(this);
}
} // namespace Teakra

View File

@ -3,14 +3,11 @@
#include <functional>
#include <utility>
#include "common_types.h"
#include "core_timing.h"
namespace Teakra {
class Timer : public CoreTiming::Callbacks {
class Timer {
public:
Timer(CoreTiming& core_timing);
enum class CountMode : u16 {
Single = 0,
AutoRestart = 1,
@ -21,10 +18,11 @@ public:
void Reset();
void Restart();
void Tick(u64 ticks) override;
void TickEvent();
u64 GetMaxSkip() const override;
void Skip(u64 ticks) override;
void Tick(u64 ticks);
u64 GetMaxSkip() const;
void Skip(u64 ticks);
u16 update_mmio = 0;
u16 pause = 0;