<commit_before>// 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/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) << 11);
}

// 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 = 0x400;

  dif_spi_device_t spi_ = {
      .params = {.base_addr = dev().region()},
      .rx_fifo_len = kFifoLen,
      .tx_fifo_len = kFifoLen,
  };

  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, 0x1, 0x1}});
  EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET,
                {{SPI_DEVICE_STATUS_ABORT_DONE, 0x1}});

  EXPECT_EQ(dif_spi_device_abort(&spi_), kDifSpiDeviceOk);
}

TEST_F(AbortTest, Delayed) {
  EXPECT_MASK32(SPI_DEVICE_CONTROL_REG_OFFSET,
                {{SPI_DEVICE_CONTROL_ABORT, 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, 0x1}});

  EXPECT_EQ(dif_spi_device_abort(&spi_), kDifSpiDeviceOk);
}

TEST_F(AbortTest, NullArgs) {
  EXPECT_EQ(dif_spi_device_abort(nullptr), kDifSpiDeviceBadArg);
}

class ConfigTest : public SpiTest {};

TEST_F(ConfigTest, BasicInit) {
  EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
                 {
                     {SPI_DEVICE_CFG_CPOL, 0},
                     {SPI_DEVICE_CFG_CPHA, 0},
                     {SPI_DEVICE_CFG_TX_ORDER, 0},
                     {SPI_DEVICE_CFG_RX_ORDER, 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, 0x400 - 1},
                 });
  EXPECT_WRITE32(SPI_DEVICE_TXF_ADDR_REG_OFFSET,
                 {
                     {SPI_DEVICE_TXF_ADDR_BASE_OFFSET, 0x400},
                     {SPI_DEVICE_TXF_ADDR_LIMIT_OFFSET, 0x800 - 1},
                 });

  EXPECT_EQ(dif_spi_device_configure(&spi_, config_), kDifSpiDeviceOk);
}

TEST_F(ConfigTest, ComplexInit) {
  config_.clock_polarity = kDifSpiDeviceEdgeNegative;
  config_.data_phase = kDifSpiDeviceEdgePositive;
  config_.tx_order = kDifSpiDeviceBitOrderLsbToMsb;
  config_.rx_fifo_timeout = 42;
  config_.rx_fifo_len = 0x24;

  EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
                 {
                     {SPI_DEVICE_CFG_CPOL, 1},
                     {SPI_DEVICE_CFG_CPHA, 1},
                     {SPI_DEVICE_CFG_TX_ORDER, 1},
                     {SPI_DEVICE_CFG_RX_ORDER, 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},
                 });<commit_msg>[dif] Clean up the SPI unit test slightly<commit_after>// 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/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) << 11);
}

// 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 = 0x400;

  dif_spi_device_t spi_ = {
      .params = {.base_addr = dev().region()},
      .rx_fifo_len = kFifoLen,
      .tx_fifo_len = kFifoLen,
  };

  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, 0x1, 0x1}});
  EXPECT_READ32(SPI_DEVICE_STATUS_REG_OFFSET,
                {{SPI_DEVICE_STATUS_ABORT_DONE, 0x1}});

  EXPECT_EQ(dif_spi_device_abort(&spi_), kDifSpiDeviceOk);
}

TEST_F(AbortTest, Delayed) {
  EXPECT_MASK32(SPI_DEVICE_CONTROL_REG_OFFSET,
                {{SPI_DEVICE_CONTROL_ABORT, 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, 0x1}});

  EXPECT_EQ(dif_spi_device_abort(&spi_), kDifSpiDeviceOk);
}

TEST_F(AbortTest, NullArgs) {
  EXPECT_EQ(dif_spi_device_abort(nullptr), kDifSpiDeviceBadArg);
}

class ConfigTest : public SpiTest {};

TEST_F(ConfigTest, BasicInit) {
  EXPECT_WRITE32(SPI_DEVICE_CFG_REG_OFFSET,
                 {
                     {SPI_DEVICE_CFG_CPOL, 0},
                     {SPI_DEVICE_CFG_CPHA, 0},
                     {SPI_DEVICE_CFG_TX_ORDER, 0},
                     {SPI_DEVICE_CFG_RX_ORDER, 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, 0x400 - 1},
                 });
  EXPECT_WRITE32(SPI_DEVICE_TXF_ADDR_REG_OFFSET,
                 {
                     {SPI_DEVICE_TXF_ADDR_BASE_OFFSET, 0x400},
                     {SPI_DEVICE_TXF_ADDR_LIMIT_OFFSET, 0x800 - 1},
                 });

  EXPECT_EQ(dif_spi_device_configure(&spi_, config_), kDifSpiDeviceOk);
}

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, 1},
                     {SPI_DEVICE_CFG_CPHA, 1},
                     {SPI_DEVICE_CFG_TX_ORDER, 1},
                     {SPI_DEVICE_CFG_RX_ORDER, 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},
                 });
{'fraction_non_alphanumeric': 0.09889860338367208, 'fraction_numerical': 0.023844669013284886, 'mean_word_length': 2.9586516853932583, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5892262', 'n_tokens_mistral': 3375, 'n_tokens_neox': 3208, 'n_words': 453}