-
Notifications
You must be signed in to change notification settings - Fork 193
Expand file tree
/
Copy pathmcal_gpt.cpp
More file actions
136 lines (112 loc) · 4.04 KB
/
mcal_gpt.cpp
File metadata and controls
136 lines (112 loc) · 4.04 KB
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
///////////////////////////////////////////////////////////////////////////////
// Copyright Christopher Kormanyos 2022 - 2024.
// Distributed under the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <cstddef>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <mcal_gpt.h>
#include <mcal_reg.h>
#include <util/utility/util_two_part_data_manipulation.h>
namespace
{
[[nodiscard]] auto gpt_is_initialized() noexcept -> bool&;
[[nodiscard]] auto gpt_is_initialized() noexcept -> bool&
{
static bool is_init { };
return is_init;
}
}
namespace local
{
auto get_consistent_microsecond_tick() noexcept -> mcal::gpt::value_type;
auto constexpr to_microseconds(std::uint64_t tick_val) noexcept -> std::uint64_t;
auto constexpr to_microseconds(std::uint64_t tick_val) noexcept -> std::uint64_t
{
// The frequency of the underlying 64-bit tick is 32.768kHz
// Consider the following tick scaling from 32.768kHz to 1MHz:
// (((t * 61) + 1)/2) + (((t * 9) + 256)/512)
// Test case: t = 32768 --> 999,424
// + 576
// ---------
// 1,000,000
return
static_cast<std::uint64_t>
(
static_cast<std::uint64_t>
(
static_cast<std::uint64_t>
(
static_cast<std::uint64_t>
(
tick_val * static_cast<std::uint8_t>(UINT8_C(61))
)
+ static_cast<std::uint8_t>(UINT8_C(1))
)
/ static_cast<std::uint8_t>(UINT8_C(2))
)
+
static_cast<std::uint64_t>
(
static_cast<std::uint64_t>
(
static_cast<std::uint64_t>
(
tick_val * static_cast<std::uint8_t>(UINT8_C(9))
)
+ static_cast<std::uint16_t>(UINT16_C(256))
)
/ static_cast<std::uint16_t>(UINT16_C(512))
)
);
}
auto read_lo = []() -> std::uint32_t { return mcal::reg::reg_access_static<std::uint32_t, std::uint32_t, mcal::reg::clint_mtime >::reg_get(); };
auto read_hi = []() -> std::uint32_t { return mcal::reg::reg_access_static<std::uint32_t, std::uint32_t, mcal::reg::clint_mtimeh>::reg_get(); };
}
void mcal::gpt::init(const config_type*)
{
if(!gpt_is_initialized())
{
using clint_mtimecmp_reg_address_type = std::uint32_t;
using clint_mtimecmp_reg_value_type = std::uint64_t;
using clint_mtimecmp_reg_set_type =
mcal::reg::reg_access_static<clint_mtimecmp_reg_address_type,
clint_mtimecmp_reg_value_type,
mcal::reg::clint_mtimecmp,
(std::numeric_limits<clint_mtimecmp_reg_value_type>::max)()>;
static_assert(std::is_same<typename clint_mtimecmp_reg_set_type::register_value_type, clint_mtimecmp_reg_value_type>::value,
"Error: Unexpected clint_mtimecmp register value type");
// Set the 64-bit mtimer compare register to its maximum value.
// This results in an essentially infinite timeout.
clint_mtimecmp_reg_set_type::reg_set();
gpt_is_initialized() = true;
}
}
mcal::gpt::value_type mcal::gpt::secure::get_time_elapsed()
{
return (gpt_is_initialized() ? local::get_consistent_microsecond_tick()
: static_cast<mcal::gpt::value_type>(UINT8_C(0)));
}
auto local::get_consistent_microsecond_tick() noexcept -> mcal::gpt::value_type
{
auto consistent_unscaled_tick = std::uint64_t { };
for(;;)
{
const volatile std::uint32_t mt_lo1 = read_lo();
const volatile std::uint32_t mt_hi = read_hi();
const volatile std::uint32_t mt_lo2 = read_lo();
if(mt_lo2 >= mt_lo1)
{
consistent_unscaled_tick = util::make_long(mt_lo1, mt_hi);
break;
}
}
return
static_cast<mcal::gpt::value_type>
(
to_microseconds(consistent_unscaled_tick)
);
}