Software APIs
uart_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 
5 #include "sw/device/silicon_creator/lib/drivers/uart.h"
6 
7 #include <time.h>
8 
9 #include "gtest/gtest.h"
12 #include "sw/device/lib/base/mock_abs_mmio.h"
13 #include "sw/device/silicon_creator/testing/rom_test.h"
14 
16 #include "uart_regs.h" // Generated.
17 
18 namespace uart_unittest {
19 namespace {
20 
21 #if 0
22 // We supply `ibex_mcycle` and `to_cpu_cycles` because these target-specific
23 // functions do not exist in the host environment. Because their purpose is
24 // to measure time for timeouts, we simply return time in microseconds.
25 
26 extern "C" {
27 uint64_t ibex_mcycle() {
28  struct timespec tp;
29  clock_gettime(CLOCK_MONOTONIC, &tp);
30  return tp.tv_sec * 1000000 + tp.tv_nsec / 1000;
31 }
32 
33 uint64_t to_cpu_cycles(uint64_t usec) { return usec; }
34 } // extern "C"
35 #endif
36 
37 const std::vector<uint8_t> kBytesArray = {
38  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
39  'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
40  'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
41 };
42 
43 class UartTest : public rom_test::RomTest {
44  protected:
45  uint32_t base_ = TOP_EARLGREY_UART0_BASE_ADDR;
46  rom_test::MockAbsMmio mmio_;
47 
48  void ExpectDeviceReset() {
49  EXPECT_ABS_WRITE32(base_ + UART_CTRL_REG_OFFSET, 0);
50  EXPECT_ABS_WRITE32(base_ + UART_FIFO_CTRL_REG_OFFSET,
51  {
52  {UART_FIFO_CTRL_RXRST_BIT, true},
53  {UART_FIFO_CTRL_TXRST_BIT, true},
54  });
55  EXPECT_ABS_WRITE32(base_ + UART_OVRD_REG_OFFSET, 0);
56  EXPECT_ABS_WRITE32(base_ + UART_TIMEOUT_CTRL_REG_OFFSET, 0);
57  EXPECT_ABS_WRITE32(base_ + UART_INTR_ENABLE_REG_OFFSET, 0);
58  EXPECT_ABS_WRITE32(base_ + UART_INTR_STATE_REG_OFFSET,
59  std::numeric_limits<uint32_t>::max());
60  }
61 };
62 
63 class InitTest : public UartTest {};
64 
65 TEST_F(InitTest, Initialize) {
66  ExpectDeviceReset();
67 
68  EXPECT_ABS_WRITE32(base_ + UART_CTRL_REG_OFFSET,
69  {
70  {UART_CTRL_TX_BIT, true},
71  {UART_CTRL_NCO_OFFSET, 1},
72  });
73  EXPECT_ABS_WRITE32(base_ + UART_INTR_ENABLE_REG_OFFSET, 0);
74 
75  uart_init(1);
76 }
77 
78 class BytesSendTest : public UartTest {
79  protected:
80  /**
81  * Sets TX bytes expectations.
82  *
83  * Every sent byte by the "send bytes" routine is expected to result in the
84  * STATUS read of 0 (FIFO not full), and write to WDATA.
85  */
86  void ExpectSendBytes(int num_elements = kBytesArray.size()) {
87  ASSERT_LE(num_elements, kBytesArray.size());
88  for (int i = 0; i < num_elements; ++i) {
89  uint32_t value = static_cast<uint32_t>(kBytesArray[i]);
90  EXPECT_ABS_READ32(base_ + UART_STATUS_REG_OFFSET,
91  {{UART_STATUS_TXFULL_BIT, false}});
92  EXPECT_ABS_WRITE32(base_ + UART_WDATA_REG_OFFSET, value);
93  EXPECT_ABS_READ32(base_ + UART_STATUS_REG_OFFSET,
94  {{UART_STATUS_TXIDLE_BIT, true}});
95  }
96  }
97 };
98 
99 TEST_F(BytesSendTest, SendBuffer) {
100  ExpectSendBytes();
101  // Calling uart_write implicitly tests uart_putchar.
102  uart_write(kBytesArray.data(), kBytesArray.size());
103 }
104 
105 TEST_F(BytesSendTest, SendByteBusy) {
106  // FIFO full for one cycle, then empty.
107  EXPECT_ABS_READ32(base_ + UART_STATUS_REG_OFFSET,
108  {{UART_STATUS_TXFULL_BIT, true}});
109  EXPECT_ABS_READ32(base_ + UART_STATUS_REG_OFFSET,
110  {{UART_STATUS_TXFULL_BIT, false}});
111 
112  // The value sent is 'X'
113  EXPECT_ABS_WRITE32(base_ + UART_WDATA_REG_OFFSET, 'X');
114 
115  // Transmitter busy for one cycle, then idle.
116  EXPECT_ABS_READ32(base_ + UART_STATUS_REG_OFFSET,
117  {{UART_STATUS_TXIDLE_BIT, false}});
118  EXPECT_ABS_READ32(base_ + UART_STATUS_REG_OFFSET,
119  {{UART_STATUS_TXIDLE_BIT, true}});
120 
121  uart_putchar('X');
122 }
123 
124 TEST_F(UartTest, RecvByte) {
125  EXPECT_ABS_READ32(base_ + UART_STATUS_REG_OFFSET,
126  {{UART_STATUS_RXEMPTY_BIT, false}});
127  EXPECT_ABS_READ32(base_ + UART_RDATA_REG_OFFSET, 'A');
128  int result = uart_getchar(1);
129  EXPECT_EQ(result, 'A');
130 }
131 
132 TEST_F(UartTest, RecvTimeout) {
133  // The uart receive function will keep polling the status register for RX FIFO
134  // status. Return RXEMPTY every time.
135  EXPECT_CALL(::rom_test::MockAbsMmio::Instance(),
136  Read32(base_ + UART_STATUS_REG_OFFSET))
137  .WillRepeatedly(testing::Return(
138  mock_mmio::ToInt<uint32_t>({{UART_STATUS_RXEMPTY_BIT, true}})));
139  int result = uart_getchar(1);
140  EXPECT_EQ(result, -1);
141 }
142 
143 TEST_F(UartTest, BreakDetect) {
144  // The break detect function will continuously poll the UART value register to
145  // observe the sampled value on the RX line. A break condition over the
146  // measured period will always return a value of zero.
147  EXPECT_CALL(::rom_test::MockAbsMmio::Instance(),
148  Read32(base_ + UART_VAL_REG_OFFSET))
149  .WillRepeatedly(testing::Return(mock_mmio::ToInt<uint32_t>(0)));
150  hardened_bool_t result = uart_break_detect(1);
151  EXPECT_EQ(result, kHardenedBoolTrue);
152 }
153 
154 TEST_F(UartTest, NoBreakDetect) {
155  // The break detect function will continuously poll the UART value register to
156  // observe the sampled value on the RX line. Any non-zero bit detected on the
157  // RX line means we don't have a break condition.
158  EXPECT_ABS_READ32(base_ + UART_VAL_REG_OFFSET, 1);
159  hardened_bool_t result = uart_break_detect(1);
160  EXPECT_EQ(result, kHardenedBoolFalse);
161 }
162 
163 } // namespace
164 } // namespace uart_unittest