1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
#pragma once
#include <chrono>
namespace nes
{
/// A cycle count that can be used for multiple components.
///
/// Each component can have a different clock frequency and this structure offers conversions between different
/// cycle counts.
class cycle_count
{
friend constexpr auto operator+(cycle_count, cycle_count) -> cycle_count;
friend constexpr auto operator-(cycle_count, cycle_count) -> cycle_count;
friend constexpr auto operator*(std::uint64_t, cycle_count) -> cycle_count;
friend constexpr auto operator*(cycle_count, std::uint64_t) -> cycle_count;
friend constexpr auto operator/(cycle_count, cycle_count) -> std::uint64_t;
std::uint64_t units_{ 0 }; // The most fine-granular cycle count (here: PPU cycles).
static constexpr auto ppu_cycle() -> cycle_count { return cycle_count{ 1 }; }
static constexpr auto cpu_cycle() -> cycle_count { return cycle_count{ 3 }; }
static constexpr auto second() -> cycle_count { return 1789773 * cpu_cycle(); }
public:
constexpr explicit cycle_count() = default;
constexpr auto operator+=(cycle_count const other) -> cycle_count& { return *this = *this + other; }
constexpr auto operator*=(std::uint64_t const other) -> cycle_count& { return *this = *this * other; }
static constexpr auto from_units(std::uint64_t const units) -> cycle_count
{
return cycle_count{ units };
}
static constexpr auto from_duration(std::chrono::microseconds const duration) -> cycle_count
{
return from_units(static_cast<std::uint64_t>(duration.count()) * second().get_units() / (1000 * 1000));
}
static constexpr auto from_cpu(std::uint64_t const cpu_cycles) -> cycle_count
{
return cpu_cycles * cpu_cycle();
}
static constexpr auto from_ppu(std::uint64_t const ppu_cycles) -> cycle_count
{
return ppu_cycles * ppu_cycle();
}
/// Value in implementation-defined units.
constexpr auto get_units() const -> std::uint64_t { return units_; }
constexpr auto to_duration() const -> std::chrono::microseconds
{
return std::chrono::microseconds{ get_units() * 1000 * 1000 / second().get_units() };
}
constexpr auto to_cpu() const -> std::uint64_t
{
return *this / cpu_cycle();
}
constexpr auto to_ppu() const -> std::uint64_t
{
return *this / ppu_cycle();
}
private:
constexpr explicit cycle_count(std::uint64_t const units)
: units_{ units }
{
}
};
constexpr auto operator==(cycle_count const a, cycle_count const b) -> bool { return a.get_units() == b.get_units(); }
constexpr auto operator!=(cycle_count const a, cycle_count const b) -> bool { return a.get_units() != b.get_units(); }
constexpr auto operator<(cycle_count const a, cycle_count const b) -> bool { return a.get_units() < b.get_units(); }
constexpr auto operator>(cycle_count const a, cycle_count const b) -> bool { return a.get_units() > b.get_units(); }
constexpr auto operator<=(cycle_count const a, cycle_count const b) -> bool { return a.get_units() <= b.get_units(); }
constexpr auto operator>=(cycle_count const a, cycle_count const b) -> bool { return a.get_units() >= b.get_units(); }
constexpr auto operator+(cycle_count const a, cycle_count const b) -> cycle_count { return cycle_count{ a.get_units() + b.get_units() }; }
constexpr auto operator-(cycle_count const a, cycle_count const b) -> cycle_count { return cycle_count{ a.get_units() - b.get_units() }; }
constexpr auto operator*(std::uint64_t const a, cycle_count const b) -> cycle_count { return cycle_count{ a * b.get_units() }; }
constexpr auto operator*(cycle_count const a, std::uint64_t const b) -> cycle_count { return cycle_count{ a.get_units() * b }; }
constexpr auto operator/(cycle_count const a, cycle_count const b) -> std::uint64_t { return a.get_units() / b.get_units(); }
} // namespace nes
|