Software APIs
rv_timer_smoketest.c
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 
5 #include "dt/dt_api.h" // Generated
6 #include "dt/dt_rv_timer.h" // Generated
10 #include "sw/device/lib/runtime/irq.h"
12 #include "sw/device/lib/testing/test_framework/check.h"
14 
15 static dif_rv_timer_t timer;
16 static dt_rv_timer_t kRvTimerDt = (dt_rv_timer_t)0;
17 static_assert(kDtRvTimerCount >= 1,
18  "This test requires at least one RV Timer instance");
19 
20 // Flag for checking whether the interrupt handler was called. When the handler
21 // is entered, this value *must* be set to false, to catch false positives.
22 //
23 // This variable is volatile, since it may suddenly change from the compiler's
24 // perspective (e.g., due to an interrupt firing).
25 static volatile bool irq_fired = true;
26 
27 // NOTE: PLIC targets need not line up with hart ids; in the future, we should
28 // generate hart ID constants elsewhere.
29 static const uint32_t kHart = 0;
30 static const uint32_t kComparator = 0;
31 
32 static const uint64_t kTickFreqHz = 1000 * 1000; // 1 MHz.
33 
34 static void test_handler(void) {
35  CHECK(!irq_fired, "Entered IRQ handler, but `irq_fired` was not false!");
36 
37  bool irq_flag;
38  CHECK_DIF_OK(dif_rv_timer_irq_is_pending(
39  &timer, kDtRvTimerIrqTimerExpiredHart0Timer0, &irq_flag));
40  CHECK(irq_flag, "Entered IRQ handler but the expected IRQ flag wasn't set!");
41 
42  CHECK_DIF_OK(
44  CHECK_DIF_OK(dif_rv_timer_irq_acknowledge(
45  &timer, kDtRvTimerIrqTimerExpiredHart0Timer0));
46 
47  irq_fired = true;
48 }
49 
50 // Override default OTTF timer ISR.
51 void ottf_timer_isr(uint32_t *exc_info) {
52  LOG_INFO("Entering handler_irq_timer()");
53  test_handler();
54  LOG_INFO("Exiting handler_irq_timer()");
55 }
56 
57 OTTF_DEFINE_TEST_CONFIG();
58 
59 bool test_main(void) {
60  irq_global_ctrl(true);
61  irq_timer_ctrl(true);
62 
63  CHECK_DIF_OK(dif_rv_timer_init_from_dt(kRvTimerDt, &timer));
64  CHECK_DIF_OK(dif_rv_timer_reset(&timer));
65 
66  dif_rv_timer_tick_params_t tick_params;
68  dt_clock_frequency(dt_rv_timer_clock(kRvTimerDt, kDtRvTimerClockClk)),
69  kTickFreqHz, &tick_params));
70  CHECK_DIF_OK(dif_rv_timer_set_tick_params(&timer, kHart, tick_params));
71  CHECK_DIF_OK(dif_rv_timer_irq_set_enabled(
72  &timer, kDtRvTimerIrqTimerExpiredHart0Timer0, kDifToggleEnabled));
73 
74  uint64_t current_time;
75  // Logs over UART incur a large runtime overhead. To accommodate that, the
76  // timer deadline needs to be large as well. In DV simulations, logs are not
77  // sent over UART, so we can reduce the runtime / sim time with a much shorter
78  // deadline (30 ms vs 100 us).
79  uint64_t kDeadline =
80  (kDeviceType == kDeviceSimDV) ? 100 /* 100 us */ : 30000 /* 30 ms */;
81  CHECK_DIF_OK(dif_rv_timer_counter_read(&timer, kHart, &current_time));
82  LOG_INFO("Current time: %d; timer theshold: %d", (uint32_t)current_time,
83  (uint32_t)(current_time + kDeadline));
84  CHECK_DIF_OK(
85  dif_rv_timer_arm(&timer, kHart, kComparator, current_time + kDeadline));
86 
87  irq_fired = false;
88  CHECK_DIF_OK(
90 
91  LOG_INFO("Waiting...");
92  while (!irq_fired) {
94  }
95 
96  return true;
97 }