blob: 5c4f94c9ebba54b43420f80c90f1c17856de3699 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/dif/dif_spi_device.h"
#include <limits>
#include "gtest/gtest.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/base/testing/mock_mmio.h"
#include "spi_device_regs.h" // Generated.
namespace dif_spi_device_unittest {
namespace {
using ::mock_mmio::LeInt;
using ::mock_mmio::MmioTest;
using ::mock_mmio::MockDevice;
// Convenience function for assembling a phased FIFO pointer.
uintptr_t FifoPtr(uintptr_t offset, bool phase) {
return offset | (static_cast<uintptr_t>(phase) << 12);
}
// Convenience function for generating a vector full of noisy data.
std::vector<char> MakeBlob(size_t len) {
std::vector<char> buf;
buf.resize(len);
uint8_t val = 1;
for (auto &c : buf) {
c = val;
val *= 31;
}
return buf;
}
class SpiTest : public testing::Test, public MmioTest {
protected:
static const uint16_t kFifoLen = 0x800;
dif_spi_device_t spi_ = {
.base_addr = dev().region(),
};
dif_spi_device_config_t config_ = {
.clock_polarity = kDifSpiDeviceEdgePositive,
.data_phase = kDifSpiDeviceEdgeNegative,
.tx_order = kDifSpiDeviceBitOrderMsbToLsb,
.rx_order = kDifSpiDeviceBitOrderMsbToLsb,
.rx_fifo_timeout = 63,
.rx_fifo_len = kFifoLen,
.tx_fifo_len = kFifoLen,
};
};
class AbortTest : public SpiTest {};
TEST_F(AbortTest, Immediate) {
EXPECT_MASK32(SPI_DEVICE_CONTROL_REG_OFFSET,
{{SPI_DEVICE_CONTROL_ABORT_BIT, 0x1, 0x1}});
EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET,
{{SPI_DEVICE_STATUS_ABORT_DONE_BIT, 0x1}});
EXPECT_EQ(dif_spi_device_abort(&spi_), kDifOk);
}
TEST_F(AbortTest, Delayed) {
EXPECT_MASK32(SPI_DEVICE_CONTROL_REG_OFFSET,
{{SPI_DEVICE_CONTROL_ABORT_BIT, 0x1, 0x1}});
EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET, 0);
EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET, 0);
EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET, 0);
EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET, 0);
EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET, 0);
EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET, 0);
EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET,
{{SPI_DEVICE_STATUS_ABORT_DONE_BIT, 0x1}});
EXPECT_EQ(dif_spi_device_abort(&spi_), kDifOk);
}
TEST_F(AbortTest, NullArgs) {
EXPECT_EQ(dif_spi_device_abort(nullptr), kDifBadArg);
}
class ConfigTest : public SpiTest {};
TEST_F(ConfigTest, BasicInit) {
EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
{
{SPI_DEVICE_CFG_CPOL_BIT, 0},
{SPI_DEVICE_CFG_CPHA_BIT, 0},
{SPI_DEVICE_CFG_TX_ORDER_BIT, 0},
{SPI_DEVICE_CFG_RX_ORDER_BIT, 0},
{SPI_DEVICE_CFG_TIMER_V_OFFSET, config_.rx_fifo_timeout},
});
EXPECT_WRITE32(SPI_DEVICE_RXF_ADDR_REG_OFFSET,
{
{SPI_DEVICE_RXF_ADDR_BASE_OFFSET, 0x000},
{SPI_DEVICE_RXF_ADDR_LIMIT_OFFSET, 0x800 - 1},
});
EXPECT_WRITE32(SPI_DEVICE_TXF_ADDR_REG_OFFSET,
{
{SPI_DEVICE_TXF_ADDR_BASE_OFFSET, 0x800},
{SPI_DEVICE_TXF_ADDR_LIMIT_OFFSET, 0x1000 - 1},
});
EXPECT_EQ(dif_spi_device_configure(&spi_, &config_), kDifOk);
}
TEST_F(ConfigTest, ComplexInit) {
config_ = {
.clock_polarity = kDifSpiDeviceEdgeNegative,
.data_phase = kDifSpiDeviceEdgePositive,
.tx_order = kDifSpiDeviceBitOrderLsbToMsb,
.rx_order = kDifSpiDeviceBitOrderMsbToLsb,
.rx_fifo_timeout = 42,
.rx_fifo_len = 0x24,
.tx_fifo_len = kFifoLen,
};
EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
{
{SPI_DEVICE_CFG_CPOL_BIT, 1},
{SPI_DEVICE_CFG_CPHA_BIT, 1},
{SPI_DEVICE_CFG_TX_ORDER_BIT, 1},
{SPI_DEVICE_CFG_RX_ORDER_BIT, 0},
{SPI_DEVICE_CFG_TIMER_V_OFFSET, config_.rx_fifo_timeout},
});
EXPECT_WRITE32(SPI_DEVICE_RXF_ADDR_REG_OFFSET,
{
{SPI_DEVICE_RXF_ADDR_BASE_OFFSET, 0x000},
{SPI_DEVICE_RXF_ADDR_LIMIT_OFFSET, 0x023},
});
EXPECT_WRITE32(SPI_DEVICE_TXF_ADDR_REG_OFFSET,
{
{SPI_DEVICE_TXF_ADDR_BASE_OFFSET, 0x024},
{SPI_DEVICE_TXF_ADDR_LIMIT_OFFSET, 0x823},
});
EXPECT_EQ(dif_spi_device_configure(&spi_, &config_), kDifOk);
}
TEST_F(ConfigTest, NullArgs) {
EXPECT_EQ(dif_spi_device_configure(nullptr, &config_), kDifBadArg);
EXPECT_EQ(dif_spi_device_configure(&spi_, nullptr), kDifBadArg);
EXPECT_EQ(dif_spi_device_configure(nullptr, nullptr), kDifBadArg);
}
TEST_F(ConfigTest, InitSramOverflow) {
config_.rx_fifo_len = 0x1000;
EXPECT_EQ(dif_spi_device_configure(&spi_, &config_), kDifBadArg);
}
class IrqTest : public SpiTest {};
TEST_F(IrqTest, Levels) {
EXPECT_WRITE32(SPI_DEVICE_FIFO_LEVEL_REG_OFFSET,
{{SPI_DEVICE_FIFO_LEVEL_RXLVL_OFFSET, 42},
{SPI_DEVICE_FIFO_LEVEL_TXLVL_OFFSET, 123}});
EXPECT_EQ(dif_spi_device_set_irq_levels(&spi_, 42, 123), kDifOk);
}
TEST_F(IrqTest, LevelsNull) {
EXPECT_EQ(dif_spi_device_set_irq_levels(nullptr, 123, 456), kDifBadArg);
}
class RxPendingTest : public SpiTest {};
TEST_F(RxPendingTest, BothZero) {
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, 0x0},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, 0x0}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_rx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0);
}
TEST_F(RxPendingTest, InPhaseEmpty) {
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x42, true)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x42, true)}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_rx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0);
}
TEST_F(RxPendingTest, InPhase) {
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x57, true)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x42, true)}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_rx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0x15);
}
TEST_F(RxPendingTest, OutOfPhaseFull) {
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x42, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x42, true)}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_rx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0x800);
}
TEST_F(RxPendingTest, OutOfPhase) {
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x42, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x57, true)}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_rx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0x7eb);
}
TEST_F(RxPendingTest, NullArgs) {
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_rx_pending(nullptr, &config_, &bytes_remaining),
kDifBadArg);
EXPECT_EQ(dif_spi_device_rx_pending(&spi_, nullptr, &bytes_remaining),
kDifBadArg);
EXPECT_EQ(dif_spi_device_rx_pending(&spi_, &config_, nullptr), kDifBadArg);
EXPECT_EQ(dif_spi_device_rx_pending(nullptr, nullptr, &bytes_remaining),
kDifBadArg);
EXPECT_EQ(dif_spi_device_rx_pending(&spi_, nullptr, nullptr), kDifBadArg);
EXPECT_EQ(dif_spi_device_rx_pending(nullptr, nullptr, nullptr), kDifBadArg);
}
class TxPendingTest : public SpiTest {};
TEST_F(TxPendingTest, BothZero) {
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, 0x0},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, 0x0}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_tx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0);
}
TEST_F(TxPendingTest, InPhaseEmpty) {
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x42, true)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x42, true)}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_tx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0);
}
TEST_F(TxPendingTest, InPhase) {
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x57, true)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x42, true)}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_tx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0x15);
}
TEST_F(TxPendingTest, OutOfPhaseFull) {
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x42, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x42, true)}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_tx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0x800);
}
TEST_F(TxPendingTest, OutOfPhase) {
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x42, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x57, true)}});
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_tx_pending(&spi_, &config_, &bytes_remaining),
kDifOk);
EXPECT_EQ(bytes_remaining, 0x7eb);
}
TEST_F(TxPendingTest, NullArgs) {
size_t bytes_remaining;
EXPECT_EQ(dif_spi_device_tx_pending(nullptr, &config_, &bytes_remaining),
kDifBadArg);
EXPECT_EQ(dif_spi_device_tx_pending(&spi_, nullptr, &bytes_remaining),
kDifBadArg);
EXPECT_EQ(dif_spi_device_tx_pending(&spi_, &config_, nullptr), kDifBadArg);
EXPECT_EQ(dif_spi_device_tx_pending(nullptr, nullptr, &bytes_remaining),
kDifBadArg);
EXPECT_EQ(dif_spi_device_tx_pending(&spi_, nullptr, nullptr), kDifBadArg);
EXPECT_EQ(dif_spi_device_tx_pending(nullptr, nullptr, nullptr), kDifBadArg);
}
class RecvTest : public SpiTest {};
TEST_F(RecvTest, EmptyFifo) {
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x5a, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x5a, false)}});
std::string buf(16, '\0');
size_t recv_len = 0;
EXPECT_EQ(dif_spi_device_recv(&spi_, &config_, const_cast<char *>(buf.data()),
buf.size(), &recv_len),
kDifOk);
EXPECT_EQ(recv_len, 0);
buf.resize(recv_len);
EXPECT_EQ(buf, "");
}
TEST_F(RecvTest, FullFifoAligned) {
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x50, true)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x50, false)}});
auto message = MakeBlob(kFifoLen);
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET;
for (int i = 0; i < kFifoLen; i += 4) {
auto idx = fifo_base + (i + 0x50) % kFifoLen;
EXPECT_READ32(idx, LeInt(&message[i]));
}
EXPECT_WRITE32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x50, true)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x50, true)}});
std::vector<char> buf;
buf.resize(message.size() * 2);
size_t recv_len = 0;
EXPECT_EQ(
dif_spi_device_recv(&spi_, &config_, buf.data(), buf.size(), &recv_len),
kDifOk);
EXPECT_EQ(recv_len, message.size());
buf.resize(recv_len);
EXPECT_EQ(buf, message);
}
TEST_F(RecvTest, FullFifoSmallBuf) {
size_t buf_len = 0x22;
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x50, true)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x50, false)}});
auto message = MakeBlob(kFifoLen);
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET;
for (size_t i = 0; i < buf_len; i += 4) {
auto idx = fifo_base + (i + 0x50) % kFifoLen;
EXPECT_READ32(idx, LeInt(&message[i]));
}
EXPECT_WRITE32(
SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x50, true)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x50 + buf_len, false)}});
std::vector<char> buf;
buf.resize(buf_len);
size_t recv_len = 0;
EXPECT_EQ(
dif_spi_device_recv(&spi_, &config_, buf.data(), buf.size(), &recv_len),
kDifOk);
EXPECT_EQ(recv_len, buf_len);
buf.resize(recv_len);
message.resize(recv_len);
EXPECT_EQ(buf, message);
}
TEST_F(RecvTest, FullyAligned) {
std::string message = "Hello, SPI!!";
ASSERT_EQ(message.size() % 4, 0);
EXPECT_READ32(
SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(message.size(), false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x00, false)}});
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET;
EXPECT_READ32(fifo_base + 0x0, LeInt(&message[0x0]));
EXPECT_READ32(fifo_base + 0x4, LeInt(&message[0x4]));
EXPECT_READ32(fifo_base + 0x8, LeInt(&message[0x8]));
EXPECT_WRITE32(
SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(message.size(), false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(message.size(), false)}});
std::string buf(message.size() * 2, '\0');
size_t recv_len = 0;
EXPECT_EQ(dif_spi_device_recv(&spi_, &config_, const_cast<char *>(buf.data()),
buf.size(), &recv_len),
kDifOk);
EXPECT_EQ(recv_len, message.size());
buf.resize(recv_len);
EXPECT_EQ(buf, message);
}
TEST_F(RecvTest, UnalignedMessage) {
std::string message = "Hello, SPI!!";
ASSERT_EQ(message.size() % 4, 0);
uintptr_t cropped_len = 9;
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(cropped_len, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x00, false)}});
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET;
EXPECT_READ32(fifo_base + 0x0, LeInt(&message[0x0]));
EXPECT_READ32(fifo_base + 0x4, LeInt(&message[0x4]));
EXPECT_READ32(fifo_base + 0x8, LeInt(&message[0x8]));
EXPECT_WRITE32(
SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(cropped_len, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(cropped_len, false)}});
std::string buf(message.size() * 2, '\0');
size_t recv_len = 0;
EXPECT_EQ(dif_spi_device_recv(&spi_, &config_, const_cast<char *>(buf.data()),
buf.size(), &recv_len),
kDifOk);
EXPECT_EQ(recv_len, cropped_len);
buf.resize(message.size());
EXPECT_NE(buf, message);
buf.resize(recv_len);
EXPECT_EQ(buf, message.substr(0, cropped_len));
}
TEST_F(RecvTest, UnalignedStart) {
std::string message = "Hello, SPI!!";
ASSERT_EQ(message.size() % 4, 0);
uintptr_t cropped_start = 1;
uintptr_t cropped_len = 9;
EXPECT_READ32(
SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(cropped_len, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(cropped_start, false)}});
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET;
EXPECT_READ32(fifo_base + 0x0, LeInt(&message[0x0]));
EXPECT_READ32(fifo_base + 0x4, LeInt(&message[0x4]));
EXPECT_READ32(fifo_base + 0x8, LeInt(&message[0x8]));
EXPECT_WRITE32(
SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(cropped_len, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(cropped_len, false)}});
std::string buf(message.size() * 2, '\0');
size_t recv_len = 0;
EXPECT_EQ(dif_spi_device_recv(&spi_, &config_, const_cast<char *>(buf.data()),
buf.size(), &recv_len),
kDifOk);
EXPECT_EQ(recv_len, cropped_len - cropped_start);
buf.resize(message.size());
EXPECT_NE(buf, message);
buf.resize(recv_len);
EXPECT_EQ(buf, message.substr(cropped_start, cropped_len - cropped_start));
}
TEST_F(RecvTest, UnalignedSmall) {
std::string message = "Hello, SPI!!";
ASSERT_EQ(message.size() % 4, 0);
uintptr_t cropped_start = 1;
uintptr_t cropped_len = 3;
EXPECT_READ32(
SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(cropped_len, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(cropped_start, false)}});
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET;
EXPECT_READ32(fifo_base + 0x0, LeInt(&message[0x0]));
EXPECT_WRITE32(
SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(cropped_len, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(cropped_len, false)}});
std::string buf(message.size() * 2, '\0');
size_t recv_len = 0;
EXPECT_EQ(dif_spi_device_recv(&spi_, &config_, const_cast<char *>(buf.data()),
buf.size(), &recv_len),
kDifOk);
EXPECT_EQ(recv_len, cropped_len - cropped_start);
buf.resize(message.size());
EXPECT_NE(buf, message);
buf.resize(recv_len);
EXPECT_EQ(buf, message.substr(cropped_start, cropped_len - cropped_start));
}
TEST_F(RecvTest, NullArgs) {
std::string buf(16, '\0');
size_t recv_len;
EXPECT_EQ(
dif_spi_device_recv(nullptr, &config_, const_cast<char *>(buf.data()),
buf.size(), &recv_len),
kDifBadArg);
EXPECT_EQ(dif_spi_device_recv(&spi_, nullptr, const_cast<char *>(buf.data()),
buf.size(), &recv_len),
kDifBadArg);
EXPECT_EQ(
dif_spi_device_recv(&spi_, &config_, nullptr, buf.size(), &recv_len),
kDifBadArg);
EXPECT_READ32(SPI_DEVICE_RXF_PTR_REG_OFFSET,
{{SPI_DEVICE_RXF_PTR_WPTR_OFFSET, FifoPtr(0x5a, false)},
{SPI_DEVICE_RXF_PTR_RPTR_OFFSET, FifoPtr(0x5a, false)}});
EXPECT_EQ(dif_spi_device_recv(&spi_, &config_, const_cast<char *>(buf.data()),
buf.size(), nullptr),
kDifOk);
}
class SendTest : public SpiTest {};
TEST_F(SendTest, FullFifo) {
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x5a, true)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x5a, false)}});
std::string message = "Hello, SPI!!";
size_t send_len = 0;
EXPECT_EQ(dif_spi_device_send(&spi_, &config_, message.data(), message.size(),
&send_len),
kDifOk);
EXPECT_EQ(send_len, 0);
}
TEST_F(SendTest, EmptyToFull) {
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x50, true)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x50, true)}});
auto message = MakeBlob(kFifoLen);
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET + config_.rx_fifo_len;
for (int i = 0; i < kFifoLen; i += 4) {
auto idx = fifo_base + (i + 0x50) % kFifoLen;
EXPECT_WRITE32(idx, LeInt(&message[i]));
}
EXPECT_WRITE32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x50, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x50, true)}});
size_t sent_len = 0;
EXPECT_EQ(dif_spi_device_send(&spi_, &config_, message.data(), message.size(),
&sent_len),
kDifOk);
EXPECT_EQ(sent_len, message.size());
}
TEST_F(SendTest, AlmostFull) {
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x4e, true)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x50, false)}});
std::string message = "Hello, world!";
uintptr_t value = 0;
memcpy(&value, message.data(), 2);
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET + config_.rx_fifo_len;
EXPECT_MASK32(fifo_base + 0x4c, {{0x10, 0xffff, value}});
EXPECT_WRITE32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x50, true)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x50, false)}});
size_t sent_len = 0;
EXPECT_EQ(dif_spi_device_send(&spi_, &config_, message.data(), message.size(),
&sent_len),
kDifOk);
EXPECT_EQ(sent_len, 2);
}
TEST_F(SendTest, FullyAligned) {
std::string message = "Hello, SPI!!";
ASSERT_EQ(message.size() % 4, 0);
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x00, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x00, false)}});
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET + config_.rx_fifo_len;
EXPECT_WRITE32(fifo_base + 0x0, LeInt(&message[0x0]));
EXPECT_WRITE32(fifo_base + 0x4, LeInt(&message[0x4]));
EXPECT_WRITE32(fifo_base + 0x8, LeInt(&message[0x8]));
EXPECT_WRITE32(
SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(message.size(), false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x0, false)}});
size_t send_len = 0;
EXPECT_EQ(dif_spi_device_send(&spi_, &config_, message.data(), message.size(),
&send_len),
kDifOk);
EXPECT_EQ(send_len, message.size());
}
TEST_F(SendTest, UnalignedMessage) {
std::string message = "Hello, SPI!!";
ASSERT_EQ(message.size() % 4, 0);
uintptr_t cropped_len = 9;
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x00, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x00, false)}});
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET + config_.rx_fifo_len;
EXPECT_WRITE32(fifo_base + 0x0, LeInt(&message[0x0]));
EXPECT_WRITE32(fifo_base + 0x4, LeInt(&message[0x4]));
uintptr_t value = 0;
memcpy(&value, &message[0x8], 1);
EXPECT_MASK32(fifo_base + 0x8, {{0x0, 0xff, value}});
EXPECT_WRITE32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(cropped_len, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x0, false)}});
size_t send_len = 0;
EXPECT_EQ(dif_spi_device_send(&spi_, &config_, message.data(), cropped_len,
&send_len),
kDifOk);
EXPECT_EQ(send_len, cropped_len);
}
TEST_F(SendTest, UnalignedStart) {
std::string message = "Hello, SPI!!";
ASSERT_EQ(message.size() % 4, 0);
uintptr_t cropped_start = 1;
uintptr_t cropped_len = 9;
EXPECT_READ32(
SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(cropped_start, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(cropped_start, false)}});
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET + config_.rx_fifo_len;
uintptr_t start_value = 0;
memcpy(&start_value, &message[0x0], 3);
EXPECT_MASK32(fifo_base + 0x0, {{0x8, 0xffffff, start_value}});
EXPECT_WRITE32(fifo_base + 0x4, LeInt(&message[0x3]));
uintptr_t end_value = 0;
memcpy(&end_value, &message[0x7], 2);
EXPECT_MASK32(fifo_base + 0x8, {{0x0, 0xffff, end_value}});
EXPECT_WRITE32(
SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET,
FifoPtr(cropped_len + cropped_start, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(cropped_start, false)}});
size_t send_len = 0;
EXPECT_EQ(dif_spi_device_send(&spi_, &config_, message.data(), cropped_len,
&send_len),
kDifOk);
EXPECT_EQ(send_len, cropped_len);
}
TEST_F(SendTest, UnalignedSmall) {
std::string message = "Hello, SPI!!";
ASSERT_EQ(message.size() % 4, 0);
uintptr_t cropped_start = 1;
uintptr_t cropped_len = 2;
EXPECT_READ32(
SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(cropped_start, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(cropped_start, false)}});
auto fifo_base = SPI_DEVICE_BUFFER_REG_OFFSET + config_.rx_fifo_len;
uintptr_t start_value = 0;
memcpy(&start_value, &message[0x0], 2);
EXPECT_MASK32(fifo_base + 0x0, {{0x8, 0xffff, start_value}});
EXPECT_WRITE32(
SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET,
FifoPtr(cropped_len + cropped_start, false)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(cropped_start, false)}});
size_t send_len = 0;
EXPECT_EQ(dif_spi_device_send(&spi_, &config_, message.data(), cropped_len,
&send_len),
kDifOk);
EXPECT_EQ(send_len, cropped_len);
}
TEST_F(SendTest, NullArgs) {
std::string buf(16, '\0');
size_t recv_len;
EXPECT_EQ(
dif_spi_device_send(nullptr, &config_, buf.data(), buf.size(), &recv_len),
kDifBadArg);
EXPECT_EQ(
dif_spi_device_send(&spi_, nullptr, buf.data(), buf.size(), &recv_len),
kDifBadArg);
EXPECT_EQ(
dif_spi_device_send(&spi_, &config_, nullptr, buf.size(), &recv_len),
kDifBadArg);
EXPECT_READ32(SPI_DEVICE_TXF_PTR_REG_OFFSET,
{{SPI_DEVICE_TXF_PTR_WPTR_OFFSET, FifoPtr(0x5a, true)},
{SPI_DEVICE_TXF_PTR_RPTR_OFFSET, FifoPtr(0x5a, false)}});
EXPECT_EQ(
dif_spi_device_send(&spi_, &config_, buf.data(), buf.size(), nullptr),
kDifOk);
}
} // namespace
} // namespace dif_spi_device_unittest