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/multichan_register_iface_test.cpp | |
| 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/multichan_register_iface_test.cpp')
| -rw-r--r-- | host/tests/multichan_register_iface_test.cpp | 180 |
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); + } +} |
