aboutsummaryrefslogtreecommitdiffstats
path: root/host/tests/multichan_register_iface_test.cpp
diff options
context:
space:
mode:
authormattprost <matt.prost@ni.com>2020-03-19 16:09:20 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2020-04-02 12:12:26 -0500
commit6aed4b5a45cf0057bc175e19a86888259bf17cec (patch)
treed92b825a039345957385d6d0f689dc5f4adb3c91 /host/tests/multichan_register_iface_test.cpp
parent7ad64600fe3db643ba10a88990263b13dac7d063 (diff)
downloaduhd-6aed4b5a45cf0057bc175e19a86888259bf17cec.tar.gz
uhd-6aed4b5a45cf0057bc175e19a86888259bf17cec.tar.bz2
uhd-6aed4b5a45cf0057bc175e19a86888259bf17cec.zip
rfnoc: Add multichannel register interface
This utility class implements the register access methods of reg_iface but adds built-in address translation features for consecutive instances of an RFNoC block. The register peek and poke methods accept an extra 'instance' parameter which is used to calculate the absolute address for the register access. This can be used for accessing registers for the different channels of a multi-channel block (i.e. Radio, DDC, DUC, etc). Signed-off-by: mattprost <matt.prost@ni.com>
Diffstat (limited to 'host/tests/multichan_register_iface_test.cpp')
-rw-r--r--host/tests/multichan_register_iface_test.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/host/tests/multichan_register_iface_test.cpp b/host/tests/multichan_register_iface_test.cpp
new file mode 100644
index 000000000..3a97d56cd
--- /dev/null
+++ b/host/tests/multichan_register_iface_test.cpp
@@ -0,0 +1,180 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhd/rfnoc/mock_block.hpp>
+#include <uhd/rfnoc/multichan_register_iface.hpp>
+#include <boost/test/unit_test.hpp>
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+using namespace uhd::rfnoc;
+
+namespace {
+
+constexpr uint32_t BASE_ADDR = 0x8000;
+constexpr size_t INSTANCE_SIZE = 0x1000;
+
+inline uint32_t get_addr_translation(uint32_t offset, size_t instance)
+{
+ return offset + BASE_ADDR + INSTANCE_SIZE * instance;
+}
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(test_poke32)
+{
+ auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
+ register_iface_holder mock_holder{mock_reg_iface};
+ multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
+ uint32_t addr = 0x100;
+ uint32_t data = 0x1230;
+ block_reg_iface.poke32(addr, data);
+ uint32_t abs_addr = get_addr_translation(addr, 0);
+ BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data);
+ for (size_t instance = 0; instance < 4; instance++) {
+ data = 0xabc0 | instance;
+ block_reg_iface.poke32(addr, data, instance);
+ abs_addr = get_addr_translation(addr, instance);
+ BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_peek32)
+{
+ auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
+ register_iface_holder mock_holder{mock_reg_iface};
+ multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
+ uint32_t addr = 0x200;
+ for (size_t instance = 0; instance < 4; instance++) {
+ uint32_t data = 0xdef0 | instance;
+ uint32_t abs_addr = get_addr_translation(addr, instance);
+ mock_reg_iface->read_memory[abs_addr] = data;
+ if (instance == 0) {
+ BOOST_CHECK_EQUAL(block_reg_iface.peek32(addr), data);
+ }
+ BOOST_CHECK_EQUAL(block_reg_iface.peek32(addr, instance), data);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_multi_poke32)
+{
+ auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
+ register_iface_holder mock_holder{mock_reg_iface};
+ multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
+ std::vector<uint32_t> addrs = {0, 4, 8, 12, 16, 20, 24, 28};
+ std::vector<uint32_t> data = {
+ 0x0000, 0x0010, 0x0200, 0x3000, 0x0004, 0x0050, 0x0600, 0x7000};
+ block_reg_iface.multi_poke32(addrs, data);
+ for (size_t i = 0; i < addrs.size(); i++) {
+ uint32_t abs_addr = get_addr_translation(addrs[i], 0);
+ BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data[i]);
+ }
+ std::reverse(data.begin(), data.end());
+ for (size_t instance = 0; instance < 4; instance++) {
+ block_reg_iface.multi_poke32(addrs, data, instance);
+ for (size_t i = 0; i < addrs.size(); i++) {
+ uint32_t abs_addr = get_addr_translation(addrs[i], instance);
+ BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data[i]);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_block_poke32)
+{
+ auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
+ register_iface_holder mock_holder{mock_reg_iface};
+ multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
+ uint32_t addr = 0x100;
+ std::vector<uint32_t> data = {
+ 0x0000, 0x0010, 0x0200, 0x3000, 0x0004, 0x0050, 0x0600, 0x7000};
+ block_reg_iface.block_poke32(addr, data);
+ for (size_t i = 0; i < data.size(); i++) {
+ uint32_t abs_addr = get_addr_translation(addr + i * sizeof(uint32_t), 0);
+ BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data[i]);
+ }
+ std::reverse(data.begin(), data.end());
+ for (size_t instance = 0; instance < 4; instance++) {
+ block_reg_iface.block_poke32(addr, data, instance);
+ for (size_t i = 0; i < data.size(); i++) {
+ uint32_t abs_addr =
+ get_addr_translation(addr + i * sizeof(uint32_t), instance);
+ BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data[i]);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_block_peek32)
+{
+ auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
+ register_iface_holder mock_holder{mock_reg_iface};
+ multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
+ uint32_t addr = 0x200;
+ std::vector<uint32_t> data = {
+ 0x0008, 0x0090, 0x0a00, 0xb000, 0x000c, 0x00d0, 0x0e00, 0xf000};
+ for (size_t instance = 0; instance < 4; instance++) {
+ for (size_t i = 0; i < data.size(); i++) {
+ uint32_t abs_addr =
+ get_addr_translation(addr + i * sizeof(uint32_t), instance);
+ mock_reg_iface->read_memory[abs_addr] = data[i];
+ }
+ std::vector<uint32_t> peek_data =
+ block_reg_iface.block_peek32(addr, data.size(), instance);
+ BOOST_CHECK_EQUAL(peek_data.size(), data.size());
+ for (size_t i = 0; i < data.size(); i++) {
+ BOOST_CHECK_EQUAL(peek_data[i], data[i]);
+ }
+ if (instance == 0) {
+ peek_data = block_reg_iface.block_peek32(addr, data.size());
+ BOOST_CHECK_EQUAL(peek_data.size(), data.size());
+ for (size_t i = 0; i < data.size(); i++) {
+ BOOST_CHECK_EQUAL(peek_data[i], data[i]);
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_poke64)
+{
+ auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
+ register_iface_holder mock_holder{mock_reg_iface};
+ multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
+ uint32_t addr = 0x100;
+ uint64_t data = 0xabcdef12;
+ block_reg_iface.poke64(addr, data);
+ uint32_t abs_addr = get_addr_translation(addr, 0);
+ BOOST_CHECK_EQUAL(
+ mock_reg_iface->write_memory[abs_addr], uint32_t(data & 0xFFFFFFFF));
+ BOOST_CHECK_EQUAL(
+ mock_reg_iface->write_memory[abs_addr + 4], uint32_t((data >> 32) & 0xFFFFFFFF));
+ for (size_t instance = 0; instance < 4; instance++) {
+ data = 0x12345670 | instance;
+ block_reg_iface.poke64(addr, data, instance);
+ abs_addr = get_addr_translation(addr, instance);
+ BOOST_CHECK_EQUAL(
+ mock_reg_iface->write_memory[abs_addr], uint32_t(data & 0xFFFFFFFF));
+ BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr + 4],
+ uint32_t((data >> 32) & 0xFFFFFFFF));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_peek64)
+{
+ auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
+ register_iface_holder mock_holder{mock_reg_iface};
+ multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
+ uint32_t addr = 0x200;
+ for (size_t instance = 0; instance < 4; instance++) {
+ uint64_t data = 0x9abcdef0 | instance;
+ uint32_t abs_addr = get_addr_translation(addr, instance);
+ mock_reg_iface->read_memory[abs_addr] = uint32_t(data & 0xFFFFFFFF);
+ mock_reg_iface->read_memory[abs_addr + 4] = uint32_t((data >> 32) & 0xFFFFFFFF);
+ if (instance == 0) {
+ BOOST_CHECK_EQUAL(block_reg_iface.peek64(addr), data);
+ }
+ BOOST_CHECK_EQUAL(block_reg_iface.peek64(addr, instance), data);
+ }
+}