1 //
2 // Copyright 2020 Ettus Research, a National Instruments Brand
3 //
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 //
6 
7 #include <uhd/rfnoc/mock_block.hpp>
8 #include <uhd/rfnoc/multichan_register_iface.hpp>
9 #include <boost/test/unit_test.hpp>
10 #include <algorithm>
11 #include <iostream>
12 #include <vector>
13 
14 using namespace uhd::rfnoc;
15 
16 namespace {
17 
18 constexpr uint32_t BASE_ADDR   = 0x8000;
19 constexpr size_t INSTANCE_SIZE = 0x1000;
20 
get_addr_translation(uint32_t offset,size_t instance)21 inline uint32_t get_addr_translation(uint32_t offset, size_t instance)
22 {
23     return offset + BASE_ADDR + INSTANCE_SIZE * instance;
24 }
25 
26 } // namespace
27 
BOOST_AUTO_TEST_CASE(test_poke32)28 BOOST_AUTO_TEST_CASE(test_poke32)
29 {
30     auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
31     register_iface_holder mock_holder{mock_reg_iface};
32     multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
33     uint32_t addr = 0x100;
34     uint32_t data = 0x1230;
35     block_reg_iface.poke32(addr, data);
36     uint32_t abs_addr = get_addr_translation(addr, 0);
37     BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data);
38     for (size_t instance = 0; instance < 4; instance++) {
39         data = 0xabc0 | instance;
40         block_reg_iface.poke32(addr, data, instance);
41         abs_addr = get_addr_translation(addr, instance);
42         BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data);
43     }
44 }
45 
BOOST_AUTO_TEST_CASE(test_peek32)46 BOOST_AUTO_TEST_CASE(test_peek32)
47 {
48     auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
49     register_iface_holder mock_holder{mock_reg_iface};
50     multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
51     uint32_t addr = 0x200;
52     for (size_t instance = 0; instance < 4; instance++) {
53         uint32_t data                         = 0xdef0 | instance;
54         uint32_t abs_addr                     = get_addr_translation(addr, instance);
55         mock_reg_iface->read_memory[abs_addr] = data;
56         if (instance == 0) {
57             BOOST_CHECK_EQUAL(block_reg_iface.peek32(addr), data);
58         }
59         BOOST_CHECK_EQUAL(block_reg_iface.peek32(addr, instance), data);
60     }
61 }
62 
BOOST_AUTO_TEST_CASE(test_multi_poke32)63 BOOST_AUTO_TEST_CASE(test_multi_poke32)
64 {
65     auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
66     register_iface_holder mock_holder{mock_reg_iface};
67     multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
68     std::vector<uint32_t> addrs = {0, 4, 8, 12, 16, 20, 24, 28};
69     std::vector<uint32_t> data  = {
70         0x0000, 0x0010, 0x0200, 0x3000, 0x0004, 0x0050, 0x0600, 0x7000};
71     block_reg_iface.multi_poke32(addrs, data);
72     for (size_t i = 0; i < addrs.size(); i++) {
73         uint32_t abs_addr = get_addr_translation(addrs[i], 0);
74         BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data[i]);
75     }
76     std::reverse(data.begin(), data.end());
77     for (size_t instance = 0; instance < 4; instance++) {
78         block_reg_iface.multi_poke32(addrs, data, instance);
79         for (size_t i = 0; i < addrs.size(); i++) {
80             uint32_t abs_addr = get_addr_translation(addrs[i], instance);
81             BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data[i]);
82         }
83     }
84 }
85 
BOOST_AUTO_TEST_CASE(test_block_poke32)86 BOOST_AUTO_TEST_CASE(test_block_poke32)
87 {
88     auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
89     register_iface_holder mock_holder{mock_reg_iface};
90     multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
91     uint32_t addr              = 0x100;
92     std::vector<uint32_t> data = {
93         0x0000, 0x0010, 0x0200, 0x3000, 0x0004, 0x0050, 0x0600, 0x7000};
94     block_reg_iface.block_poke32(addr, data);
95     for (size_t i = 0; i < data.size(); i++) {
96         uint32_t abs_addr = get_addr_translation(addr + i * sizeof(uint32_t), 0);
97         BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data[i]);
98     }
99     std::reverse(data.begin(), data.end());
100     for (size_t instance = 0; instance < 4; instance++) {
101         block_reg_iface.block_poke32(addr, data, instance);
102         for (size_t i = 0; i < data.size(); i++) {
103             uint32_t abs_addr =
104                 get_addr_translation(addr + i * sizeof(uint32_t), instance);
105             BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr], data[i]);
106         }
107     }
108 }
109 
BOOST_AUTO_TEST_CASE(test_block_peek32)110 BOOST_AUTO_TEST_CASE(test_block_peek32)
111 {
112     auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
113     register_iface_holder mock_holder{mock_reg_iface};
114     multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
115     uint32_t addr              = 0x200;
116     std::vector<uint32_t> data = {
117         0x0008, 0x0090, 0x0a00, 0xb000, 0x000c, 0x00d0, 0x0e00, 0xf000};
118     for (size_t instance = 0; instance < 4; instance++) {
119         for (size_t i = 0; i < data.size(); i++) {
120             uint32_t abs_addr =
121                 get_addr_translation(addr + i * sizeof(uint32_t), instance);
122             mock_reg_iface->read_memory[abs_addr] = data[i];
123         }
124         std::vector<uint32_t> peek_data =
125             block_reg_iface.block_peek32(addr, data.size(), instance);
126         BOOST_CHECK_EQUAL(peek_data.size(), data.size());
127         for (size_t i = 0; i < data.size(); i++) {
128             BOOST_CHECK_EQUAL(peek_data[i], data[i]);
129         }
130         if (instance == 0) {
131             peek_data = block_reg_iface.block_peek32(addr, data.size());
132             BOOST_CHECK_EQUAL(peek_data.size(), data.size());
133             for (size_t i = 0; i < data.size(); i++) {
134                 BOOST_CHECK_EQUAL(peek_data[i], data[i]);
135             }
136         }
137     }
138 }
139 
BOOST_AUTO_TEST_CASE(test_poke64)140 BOOST_AUTO_TEST_CASE(test_poke64)
141 {
142     auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
143     register_iface_holder mock_holder{mock_reg_iface};
144     multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
145     uint32_t addr = 0x100;
146     uint64_t data = 0xabcdef12;
147     block_reg_iface.poke64(addr, data);
148     uint32_t abs_addr = get_addr_translation(addr, 0);
149     BOOST_CHECK_EQUAL(
150         mock_reg_iface->write_memory[abs_addr], uint32_t(data & 0xFFFFFFFF));
151     BOOST_CHECK_EQUAL(
152         mock_reg_iface->write_memory[abs_addr + 4], uint32_t((data >> 32) & 0xFFFFFFFF));
153     for (size_t instance = 0; instance < 4; instance++) {
154         data = 0x12345670 | instance;
155         block_reg_iface.poke64(addr, data, instance);
156         abs_addr = get_addr_translation(addr, instance);
157         BOOST_CHECK_EQUAL(
158             mock_reg_iface->write_memory[abs_addr], uint32_t(data & 0xFFFFFFFF));
159         BOOST_CHECK_EQUAL(mock_reg_iface->write_memory[abs_addr + 4],
160             uint32_t((data >> 32) & 0xFFFFFFFF));
161     }
162 }
163 
BOOST_AUTO_TEST_CASE(test_peek64)164 BOOST_AUTO_TEST_CASE(test_peek64)
165 {
166     auto mock_reg_iface = std::make_shared<mock_reg_iface_t>();
167     register_iface_holder mock_holder{mock_reg_iface};
168     multichan_register_iface block_reg_iface{mock_holder, BASE_ADDR, INSTANCE_SIZE};
169     uint32_t addr = 0x200;
170     for (size_t instance = 0; instance < 4; instance++) {
171         uint64_t data                             = 0x9abcdef0 | instance;
172         uint32_t abs_addr                         = get_addr_translation(addr, instance);
173         mock_reg_iface->read_memory[abs_addr]     = uint32_t(data & 0xFFFFFFFF);
174         mock_reg_iface->read_memory[abs_addr + 4] = uint32_t((data >> 32) & 0xFFFFFFFF);
175         if (instance == 0) {
176             BOOST_CHECK_EQUAL(block_reg_iface.peek64(addr), data);
177         }
178         BOOST_CHECK_EQUAL(block_reg_iface.peek64(addr, instance), data);
179     }
180 }
181