diff options
author | mattprost <matt.prost@ni.com> | 2020-03-19 16:09:20 -0500 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-04-02 12:12:26 -0500 |
commit | 6aed4b5a45cf0057bc175e19a86888259bf17cec (patch) | |
tree | d92b825a039345957385d6d0f689dc5f4adb3c91 /host/tests | |
parent | 7ad64600fe3db643ba10a88990263b13dac7d063 (diff) | |
download | uhd-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')
-rw-r--r-- | host/tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/tests/multichan_register_iface_test.cpp | 180 |
2 files changed, 181 insertions, 0 deletions
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 2742c0385..3665a9d17 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -59,6 +59,7 @@ set(test_sources tx_streamer_test.cpp block_id_test.cpp rfnoc_property_test.cpp + multichan_register_iface_test.cpp ) #turn each test cpp file into an executable with an int main() function 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); + } +} |