Software APIs
dif_rv_timer_unittest.cc
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
7 #include <cstring>
8 #include <limits>
9 #include <ostream>
10 #include <stdint.h>
11 
12 #include "gtest/gtest.h"
14 #include "sw/device/lib/base/mock_mmio.h"
16 
17 #include "rv_timer_regs.h" // Generated.
18 
19 // We define global namespace == and << to make `dif_i2c_timing_params_t` work
20 // nicely with EXPECT_EQ.
22  return a.prescale == b.prescale && a.tick_step == b.tick_step;
23 }
24 
25 std::ostream &operator<<(std::ostream &os,
26  const dif_rv_timer_tick_params_t &params) {
27  // Note that `tick_step` is actually a `char`, so it doesn't print correctly.
28  auto step = static_cast<uint32_t>(params.tick_step);
29  return os << "{ .prescale = " << params.prescale << ", .tick_step = " << step
30  << " }";
31 }
32 
33 namespace dif_rv_timer_unittest {
34 namespace {
35 using ::mock_mmio::LeInt;
36 using ::mock_mmio::MmioTest;
37 using ::mock_mmio::MockDevice;
38 
39 constexpr uint32_t kFastClockSpeed = 2'000'000'000; // 2 GHz
40 constexpr uint32_t kClockSpeed = 50'000'000; // 50 MHz
41 constexpr uint32_t kSlowClockSpeed = 50; // 50 Hz
42 
43 constexpr uint32_t kSlowTimer = 1'000'000; // 1 MHz
44 constexpr uint32_t kFastTimer = 120'000'000; // 120 MHz
45 constexpr uint32_t kSluggishTimer = 3; // 3 Hz
46 
47 TEST(ApproximateParamsTest, Success) {
48  // The timer frequency devices the clock speed, so their quotient minus 1 is
49  // the prescale.
50  dif_rv_timer_tick_params_t params, expected = {
51  .prescale = 49,
52  .tick_step = 1,
53  };
55  dif_rv_timer_approximate_tick_params(kClockSpeed, kSlowTimer, &params));
56  EXPECT_EQ(params, expected);
57 }
58 
59 TEST(ApproximateParamsTest, WithStep) {
60  // 50 MHz / 5 is 10 MHz; multiplied by 12, we get 120 MHz.
61  dif_rv_timer_tick_params_t params, expected = {
62  .prescale = 4,
63  .tick_step = 12,
64  };
66  dif_rv_timer_approximate_tick_params(kClockSpeed, kFastTimer, &params));
67  EXPECT_EQ(params, expected);
68 }
69 
70 TEST(ApproximateParamsTest, UnrepresenableTooSlow) {
71  // This frequency is unrepresentable; the GCD of the clock and timer
72  // frequencies is 1, so the prescale is the clock speed, which does not fit in
73  // a u12.
76  kFastClockSpeed, kSluggishTimer, &params));
77 }
78 
79 TEST(ApproximateParamsTest, UnrepresenableTooFast) {
80  // This freqncy is unrepresentable; the GCD is 50, meaning that the step must
81  // be 2'400'000, which does not fit into a u8.
84  kFastTimer, &params));
85 }
86 
87 TEST(ApproximateParamsTest, NullArgs) {
89  kFastTimer, nullptr));
90 }
91 
92 class TimerTest : public testing::Test, public MmioTest {
93  protected:
94  dif_rv_timer_t rv_timer_ = {.base_addr = dev().region()};
95 };
96 
97 // Copy of `reg_for_hart()` in the C translation unit under test.
98 ptrdiff_t RegForHart(uint32_t hart, ptrdiff_t reg_offset) {
99  return 0x100 * hart + reg_offset;
100 }
101 
102 constexpr uint32_t kAllOnes = std::numeric_limits<uint32_t>::max();
103 
104 class ResetTest : public TimerTest {};
105 
106 TEST_F(ResetTest, Success) {
107  EXPECT_WRITE32(RV_TIMER_CTRL_REG_OFFSET, 0x0);
108 
109  for (uint32_t hart_id = 0; hart_id < RV_TIMER_PARAM_N_HARTS; ++hart_id) {
110  EXPECT_WRITE32(RegForHart(0, RV_TIMER_INTR_ENABLE0_REG_OFFSET), 0x0);
111  EXPECT_WRITE32(RegForHart(0, RV_TIMER_INTR_STATE0_REG_OFFSET), kAllOnes);
112 
113  for (uint32_t comp_id = 0; comp_id < RV_TIMER_PARAM_N_TIMERS; ++comp_id) {
114  EXPECT_WRITE32(RegForHart(0, RV_TIMER_COMPARE_UPPER0_0_REG_OFFSET),
115  kAllOnes);
116  EXPECT_WRITE32(RegForHart(0, RV_TIMER_COMPARE_LOWER0_0_REG_OFFSET),
117  kAllOnes);
118  EXPECT_WRITE32(RegForHart(0, RV_TIMER_COMPARE_UPPER0_0_REG_OFFSET),
119  kAllOnes);
120  }
121  }
122  EXPECT_WRITE32(RegForHart(0, RV_TIMER_TIMER_V_LOWER0_REG_OFFSET), 0x0);
123  EXPECT_WRITE32(RegForHart(0, RV_TIMER_TIMER_V_UPPER0_REG_OFFSET), 0x0);
124 
125  EXPECT_DIF_OK(dif_rv_timer_reset(&rv_timer_));
126 }
127 
128 TEST_F(ResetTest, NullArgs) { EXPECT_DIF_BADARG(dif_rv_timer_reset(nullptr)); }
129 
130 class SetTickParamsTest : public TimerTest {};
131 
132 TEST_F(SetTickParamsTest, Success) {
133  EXPECT_WRITE32(
134  RegForHart(0, RV_TIMER_CFG0_REG_OFFSET),
135  {{RV_TIMER_CFG0_PRESCALE_OFFSET, 400}, {RV_TIMER_CFG0_STEP_OFFSET, 25}});
136 
138  &rv_timer_, 0, {.prescale = 400, .tick_step = 25}));
139 }
140 
141 TEST_F(SetTickParamsTest, NullArgs) {
143  nullptr, 0, {.prescale = 400, .tick_step = 25}));
144 }
145 
146 TEST_F(SetTickParamsTest, BadHartId) {
148  &rv_timer_, RV_TIMER_PARAM_N_HARTS, {.prescale = 400, .tick_step = 25}));
149 }
150 
152 
153 TEST_F(CounterSetEnabledTest, Success) {
154  EXPECT_MASK32(RV_TIMER_CTRL_REG_OFFSET,
155  {{/*offset=*/0, /*mask=*/1, /*value=*/1}});
158 }
159 
160 TEST_F(CounterSetEnabledTest, NullArgs) {
163 }
164 
165 TEST_F(CounterSetEnabledTest, BadHartId) {
167  &rv_timer_, RV_TIMER_PARAM_N_HARTS, kDifToggleEnabled));
168 }
169 
170 class CounterReadTest : public TimerTest {};
171 
172 TEST_F(CounterReadTest, Success) {
173  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_UPPER0_REG_OFFSET), 0x0222'0222);
174  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_LOWER0_REG_OFFSET), 0x0333'0333);
175  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_UPPER0_REG_OFFSET), 0x0222'0222);
176 
177  uint64_t value;
178  EXPECT_DIF_OK(dif_rv_timer_counter_read(&rv_timer_, 0, &value));
179  EXPECT_EQ(value, 0x0222'0222'0333'0333);
180 }
181 
182 TEST_F(CounterReadTest, Overflow) {
183  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_UPPER0_REG_OFFSET), 0x0222'0222);
184  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_LOWER0_REG_OFFSET), 0x0333'0333);
185  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_UPPER0_REG_OFFSET), 0x0222'0223);
186 
187  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_UPPER0_REG_OFFSET), 0x0222'0223);
188  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_LOWER0_REG_OFFSET), 0x0333'0444);
189  EXPECT_READ32(RegForHart(0, RV_TIMER_TIMER_V_UPPER0_REG_OFFSET), 0x0222'0223);
190 
191  uint64_t value;
192  EXPECT_DIF_OK(dif_rv_timer_counter_read(&rv_timer_, 0, &value));
193  EXPECT_EQ(value, 0x0222'0223'0333'0444);
194 }
195 
196 TEST_F(CounterReadTest, NullArgs) {
197  uint64_t value;
198  EXPECT_DIF_BADARG(dif_rv_timer_counter_read(nullptr, 0, &value));
199  EXPECT_DIF_BADARG(dif_rv_timer_counter_read(&rv_timer_, 0, nullptr));
200 }
201 
202 TEST_F(CounterReadTest, BadHartId) {
203  uint64_t value;
205  dif_rv_timer_counter_read(&rv_timer_, RV_TIMER_PARAM_N_HARTS, &value));
206 }
207 
208 class CounterWriteTest : public TimerTest {};
209 
210 TEST_F(CounterWriteTest, Success) {
211  EXPECT_READ32(RV_TIMER_CTRL_REG_OFFSET, 0x0000'0001);
212  EXPECT_WRITE32(RV_TIMER_CTRL_REG_OFFSET, 0x0000'0000);
213  EXPECT_WRITE32(RegForHart(0, RV_TIMER_TIMER_V_LOWER0_REG_OFFSET),
214  0xDEAD'BEEF);
215  EXPECT_WRITE32(RegForHart(0, RV_TIMER_TIMER_V_UPPER0_REG_OFFSET),
216  0xCAFE'FEED);
217  EXPECT_WRITE32(RV_TIMER_CTRL_REG_OFFSET, 0x0000'0001);
218 
219  uint64_t count = 0xCAFE'FEED'DEAD'BEEF;
220  EXPECT_DIF_OK(dif_rv_timer_counter_write(&rv_timer_, 0, count));
221 }
222 
223 TEST_F(CounterWriteTest, NullArgs) {
224  uint64_t count = 0xCAFE'FEED'DEAD'BEEF;
225  EXPECT_DIF_BADARG(dif_rv_timer_counter_write(nullptr, 0, count));
226 }
227 
228 TEST_F(CounterWriteTest, BadHartId) {
229  uint64_t count = 0xCAFE'FEED'DEAD'BEEF;
231  dif_rv_timer_counter_write(&rv_timer_, RV_TIMER_PARAM_N_HARTS, count));
232 }
233 
234 class ArmTest : public TimerTest {};
235 
236 TEST_F(ArmTest, Success) {
237  auto lower_reg = RegForHart(0, RV_TIMER_COMPARE_LOWER0_0_REG_OFFSET);
238  auto upper_reg = RegForHart(0, RV_TIMER_COMPARE_UPPER0_0_REG_OFFSET);
239 
240  EXPECT_WRITE32(upper_reg, kAllOnes);
241  EXPECT_WRITE32(lower_reg, 0x0444'0555);
242  EXPECT_WRITE32(upper_reg, 0x0222'0333);
243 
244  EXPECT_DIF_OK(dif_rv_timer_arm(&rv_timer_, 0, 0, 0x0222'0333'0444'0555));
245 }
246 
247 TEST_F(ArmTest, NullArgs) {
248  EXPECT_DIF_BADARG(dif_rv_timer_arm(nullptr, 0, 0, 0x0222'0333'0444'0555));
249 }
250 
251 TEST_F(ArmTest, BadHartIdBadCompId) {
252  EXPECT_DIF_BADARG(dif_rv_timer_arm(&rv_timer_, RV_TIMER_PARAM_N_HARTS, 0,
253  0x0222'0333'0444'0555));
254  EXPECT_DIF_BADARG(dif_rv_timer_arm(&rv_timer_, 0, RV_TIMER_PARAM_N_TIMERS,
255  0x0222'0333'0444'0555));
256  EXPECT_DIF_BADARG(dif_rv_timer_arm(&rv_timer_, RV_TIMER_PARAM_N_HARTS,
257  RV_TIMER_PARAM_N_TIMERS,
258  0x0222'0333'0444'0555));
259 }
260 
261 } // namespace
262 } // namespace dif_rv_timer_unittest