aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/ic_reg_maps/gen_zbx_cpld_regs.py
blob: 0efc8a4d7ee601e7e2018fe5268b3cf9b3d6890a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# Copyright 2020 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
"""
Register map for the ZBX CPLD. Note that the ground truth for this register map
is in the fpga/usrp3/top/x400/dboards/zbx/cpld subdirectory, and can be looked
up in fpga/usrp3/top/x400/dboards/zbx/cpld/doc/ZBX_CPLD.htm

This CPLD regmap works with RevB daughterboards only.
"""

########################################################################
# Template for raw text data describing registers
# name addr[bit range inclusive] default optional enums
########################################################################
REGS_TMPL = """\
########################################################################
## SLAVE SETUP
########################################################################
BOARD_ID                    0x0000[0:15]            0
REVISION                    0x0004[0:31]            0
OLDEST_COMPAT_REVISION      0x0008[0:31]            0
SCRATCH                     0x000C[0:31]            0
GIT_HASH                    0x0010[0:31]            0
ENABLE_TX_POS_7V0           0x0040[0]               0   disable, enable
ENABLE_RX_POS_7V0           0x0040[1]               0   disable, enable
ENABLE_POS_3V3              0x0040[2]               0   disable, enable
P7V_B_STATUS                0x0044[0]               0
P7V_A_STATUS                0x0044[1]               0
PLL_REF_CLOCK_ENABLE        0x0048[0]               0   disable, enable
########################################################################
## ATR
########################################################################
CURRENT_RF0_CONFIG          0x1000[0:7]             1
CURRENT_RF1_CONFIG          0x1000[8:15]            1
CURRENT_RF0_DSA_CONFIG      0x1000[23:16]           1
CURRENT_RF1_DSA_CONFIG      0x1000[31:24]           1
RF0_OPTION                  0x1004[0:1]             0   sw_defined, classic_atr, fpga_state
RF1_OPTION                  0x1004[8:9]             0   sw_defined, classic_atr, fpga_state
RF0_DSA_OPTION              0x1004[17:16]           0   sw_defined, classic_atr, fpga_state
RF1_DSA_OPTION              0x1004[25:24]           0   sw_defined, classic_atr, fpga_state
SW_RF0_CONFIG               0x1008[0:7]             0
SW_RF1_CONFIG               0x1008[8:15]            0
SW_RF0_DSA_CONFIG           0x1008[23:16]           0
SW_RF1_DSA_CONFIG           0x1008[31:24]           0
########################################################################
## LO SPI
########################################################################
DATA                        0x1020[0:15]            0
ADDRESS                     0x1020[16:22]           0
READ_FLAG                   0x1020[23]              1   write, read
LO_SELECT                   0x1020[24:26]           0   TX0_LO1, TX0_LO2, TX1_LO1, TX1_LO2, RX0_LO1, RX0_LO2, RX1_LO1, RX1_LO2
START_TRANSACTION           0x1020[28]              0   disable, enable
SPI_READY                   0x1020[30]              0
DATA_VALID                  0x1020[31]              0
########################################################################
## LO SYNC
########################################################################
PULSE_TX0_LO1_SYNC          0x1024[0]               0
PULSE_TX0_LO2_SYNC          0x1024[1]               0
PULSE_TX1_LO1_SYNC          0x1024[2]               0
PULSE_TX1_LO2_SYNC          0x1024[3]               0
PULSE_RX0_LO1_SYNC          0x1024[4]               0
PULSE_RX0_LO2_SYNC          0x1024[5]               0
PULSE_RX1_LO1_SYNC          0x1024[6]               0
PULSE_RX1_LO2_SYNC          0x1024[7]               0
BYPASS_SYNC_REGISTER        0x1024[8]               0   disable, enable
########################################################################
## LED CONTROL
########################################################################
RX0_RX_LED[256]             0x1400[0]               0   disable, enable
RX0_TRX_LED[256]            0x1400[1]               0   disable, enable
TX0_TRX_LED[256]            0x1400[2]               0   disable, enable
RX1_RX_LED[256]             0x1400[16]              0   disable, enable
RX1_TRX_LED[256]            0x1400[17]              0   disable, enable
TX1_TRX_LED[256]            0x1400[18]              0   disable, enable
########################################################################
## PATH CONTROL - TX 0
########################################################################
TX0_IF2_1_2[256]            0x2000[0]               0   filter_2, filter_1
TX0_IF1_3[256]              0x2000[2:3]             0   filter_0_3, filter_4, filter_6, filter_5
TX0_IF1_4[256]              0x2000[4:5]             0   termination, filter_1, filter_2, filter_3
TX0_IF1_5[256]              0x2000[6:7]             0   filter_3, filter_2, filter_1, termination
TX0_IF1_6[256]              0x2000[8:9]             0   filter_5, filter_6, filter_4, filter_0_3
TX0_7[256]                  0x2000[10:11]           0   termination, no_connect, highband, lowband
TX0_RF_8[256]               0x2000[12:14]           0   invalid_0, rf_3, rf_1, invalid_1, rf_2
TX0_RF_9[256]               0x2000[16:17]           0   rf_3, rf_1, rf_2, highband
TX0_ANT_10[256]             0x2000[18:19]           0   bypass_amp, cal_loopback, lowband_amp, highband_amp
TX0_ANT_11[256]             0x2000[20:21]           0   tx_rx, highband_amp, lowband_amp, bypass_amp
TX0_LO_13[256]              0x2000[24]              0   internal, external
TX0_LO_14[256]              0x2000[26]              0   external, internal
########################################################################
## PATH CONTROL - TX 1
########################################################################
TX1_IF2_1_2[256]            0x2400[0]               0   filter_1, filter_2
TX1_IF1_3[256]              0x2400[2:3]             0   filter_5, filter_6, filter_4, filter_0_3
TX1_IF1_4[256]              0x2400[4:5]             0   filter_3, filter_2, filter_1, termination
TX1_IF1_5[256]              0x2400[6:7]             0   termination, filter_1, filter_2, filter_3
TX1_IF1_6[256]              0x2400[8:9]             0   filter_0_3, filter_4, filter_6, filter_5
TX1_7[256]                  0x2400[10:11]           0   lowband, highband, no_connect, termination
TX1_RF_8[256]               0x2400[12:14]           0   invalid_0, rf_2, rf_1, invalid_1, rf_3
TX1_RF_9[256]               0x2400[16:17]           0   highband, rf_2, rf_1, rf_3
TX1_ANT_10[256]             0x2400[18:19]           0   highband_amp, lowband_amp, bypass_amp, cal_loopback
TX1_ANT_11[256]             0x2400[20:21]           0   tx_rx, bypass_amp, lowband_amp, highband_amp
TX1_LO_13[256]              0x2400[24]              0   external, internal
TX1_LO_14[256]              0x2400[26]              0   internal, external
########################################################################
## PATH CONTROL - RX 0
########################################################################
RX0_ANT_1[256]              0x2800[0:1]             0   cal_loopback, termination, tx_rx, rx2
RX0_2[256]                  0x2800[2]               0   highband, lowband
RX0_RF_3[256]               0x2800[4:6]             0   invalid_0, rf_2, rf_1, invalid_1, rf_3
RX0_4[256]                  0x2800[8]               0   lowband, highband
RX0_IF1_5[256]              0x2800[10:11]           0   filter_4, filter_3, filter_2, filter_1
RX0_IF1_6[256]              0x2800[12:13]           0   filter_1, filter_2, filter_3, filter_4
RX0_IF2_7_8[256]            0x2800[14]              0   filter_2, filter_1
RX0_LO_9[256]               0x2800[16]              0   internal, external
RX0_LO_10[256]              0x2800[18]              0   internal, external
RX0_RF_11[256]              0x2800[20:22]           0   invalid_0, rf_3, rf_1, invalid_1, rf_2, invalid_2, invalid_3, invalid_4
########################################################################
## PATH CONTROL - RX 1
########################################################################
RX1_ANT_1[256]              0x2C00[0:1]             0   cal_loopback, tx_rx, rx2, termination
RX1_2[256]                  0x2C00[2]               0   lowband, highband
RX1_RF_3[256]               0x2C00[4:6]             0   invalid_0, rf_3, rf_1, invalid_1, rf_2
RX1_4[256]                  0x2C00[8]               0   highband, lowband
RX1_IF1_5[256]              0x2C00[10:11]           0   filter_1, filter_2, filter_3, filter_4
RX1_IF1_6[256]              0x2C00[12:13]           0   filter_4, filter_3, filter_2, filter_1
RX1_IF2_7_8[256]            0x2C00[14]              0   filter_1, filter_2
RX1_LO_9[256]               0x2C00[16]              0   external, internal
RX1_LO_10[256]              0x2C00[18]              0   external, internal
RX1_RF_11[256]              0x2C00[20:22]           0   invalid_0, rf_2, rf_1, invalid_1, rf_3, invalid_2, invalid_3, invalid_4
########################################################################
## DSA CONTROL
########################################################################
TX0_DSA1[256]               0x3000[0:4]             31
TX0_DSA2[256]               0x3000[8:12]            31
TX1_DSA1[256]               0x3400[0:4]             31
TX1_DSA2[256]               0x3400[8:12]            31
RX0_DSA1[256]               0x3800[0:3]             15
RX0_DSA2[256]               0x3800[4:7]             15
RX0_DSA3_A[256]             0x3800[8:11]            15
RX0_DSA3_B[256]             0x3800[12:15]           15
RX1_DSA1[256]               0x3C00[0:3]             15
RX1_DSA2[256]               0x3C00[4:7]             15
RX1_DSA3_A[256]             0x3C00[8:11]            15
RX1_DSA3_B[256]             0x3C00[12:15]           15
TX0_TABLE_SELECT[256]       0x4000[0:7]             0
TX1_TABLE_SELECT[256]       0x4400[0:7]             0
RX0_TABLE_SELECT[256]       0x4800[0:7]             0
RX1_TABLE_SELECT[256]       0x4C00[0:7]             0
TX0_TABLE_DSA1[256]         0x5000[0:4]             31
TX0_TABLE_DSA2[256]         0x5000[8:12]            31
TX1_TABLE_DSA1[256]         0x5400[0:4]             31
TX1_TABLE_DSA2[256]         0x5400[8:12]            31
RX0_TABLE_DSA1[256]         0x5800[0:3]             15
RX0_TABLE_DSA2[256]         0x5800[4:7]             15
RX0_TABLE_DSA3_A[256]       0x5800[8:11]            15
RX0_TABLE_DSA3_B[256]       0x5800[12:15]           15
RX1_TABLE_DSA1[256]         0x5C00[0:3]             15
RX1_TABLE_DSA2[256]         0x5C00[4:7]             15
RX1_TABLE_DSA3_A[256]       0x5C00[8:11]            15
RX1_TABLE_DSA3_B[256]       0x5C00[12:15]           15
"""

########################################################################
# Template for python methods in the body of the struct
########################################################################

PY_BODY_TMPL = """\
def get_reg(self, addr):
    "Return the value of register at address addr"
    reg = 0
    # First the regular registers
    % for addr in sorted(set([r.get_addr() for r in regs if not r.is_array])):
    if addr == ${addr}:
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
            % if reg.get_enums():
        reg |= (self.${reg.get_name()}.value & ${reg.get_mask()}) << ${reg.get_shift()}
            % else:
        reg |= (self.${reg.get_name()} & ${reg.get_mask()}) << ${reg.get_shift()}
            % endif
        % endfor
    % endfor
    # Now the arrays
    # We can do this because all arrays have a base address that is a multiple
    # of 256 (0x100). In other words, this is a hack that only works if you
    # know exactly what you're doing, which is OK in this case, because its in
    # this same file as the register map.
    array_offset = addr % 256
    base_addr = addr - array_offset
    index = int(array_offset / 4)
    % for addr in sorted(set([r.get_addr() for r in regs if r.is_array])):
    if base_addr == ${addr}:
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
        <%
        assert reg.get_array_len() == 256, "Arrays must be length 256!"
        assert reg.get_addr() % 256 == 0, "Arrays must start at a multiple of 0x100!"
        %>
        % if reg.get_enums():
        reg |= (int(self.${reg.get_name()}[index].value) & ${reg.get_mask()}) << ${reg.get_shift()}
        % else:
        reg |= (int(self.${reg.get_name()}[index]) & ${reg.get_mask()}) << ${reg.get_shift()}
        % endif
        % endfor
    % endfor
    return reg

<%
    all_addrs = set()
    for reg in regs:
        for index in range(reg.get_array_len() if reg.is_array else 1):
            all_addrs.add(reg.get_addr() + index * reg.get_addr_step_size())
%>
def get_all_regs(self):
    addrs = {
    % for addr in sorted(all_addrs):
        ${addr},
    % endfor
    }
    return addrs

def get_addr(self, reg_name):
    "returns the address of a register with the given name"
    return {
        % for reg in regs:
        '${reg.get_name()}': ${reg.get_addr()},
        % endfor
    }[reg_name]
"""


########################################################################
# Template for C++ methods in the body of the struct
########################################################################
BODY_TMPL = """\
enum class zbx_cpld_field_t {
    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))):
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
    ${reg.get_name()},
        % endfor
    % endfor
};

zbx_cpld_field_t get_field_type(const std::string& field_name) {
    % for addr in sorted(set(map(lambda r: r.get_addr(), regs))):
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
    if (field_name == "${reg.get_name()}") {
        return zbx_cpld_field_t::${reg.get_name()};
    } else
        % endfor
    % endfor
    {
        UHD_ASSERT_THROW(false);
    }
}

uint32_t get_array_size(zbx_cpld_field_t field) {
    switch(field) {
    % for addr in sorted(set([r.get_addr() for r in regs if r.is_array])):
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
    case zbx_cpld_field_t::${reg.get_name()}:
        return uint32_t(${reg.get_name()}.size());
        % endfor
    % endfor
    default:
        UHD_ASSERT_THROW(false);
        return 0;
    }
}

uint32_t get_field(zbx_cpld_field_t field) {
    switch(field) {
    % for addr in sorted(set([r.get_addr() for r in regs if not r.is_array])):
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
    case zbx_cpld_field_t::${reg.get_name()}:
        return uint32_t(${reg.get_name()});
        % endfor
    % endfor
    default:
        UHD_ASSERT_THROW(false);
        return 0;
    }
}

uint32_t get_field(zbx_cpld_field_t field, const size_t idx) {
    switch(field) {
    % for addr in sorted(set([r.get_addr() for r in regs if r.is_array])):
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
    case zbx_cpld_field_t::${reg.get_name()}:
        return uint32_t(${reg.get_name()}[idx]);
        % endfor
    % endfor
    default:
        UHD_ASSERT_THROW(false);
        return 0;
    }
}

void set_field(zbx_cpld_field_t field, uint32_t value) {
    switch(field) {
    % for addr in sorted(set([r.get_addr() for r in regs if not r.is_array])):
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
    case zbx_cpld_field_t::${reg.get_name()}:
        ${reg.get_name()} = static_cast<${reg.get_type()}>(value);
        break;
        % endfor
    % endfor
    default:
        UHD_ASSERT_THROW(false);
    }
}

void set_field(zbx_cpld_field_t field, uint32_t value, const size_t idx)
{
    switch(field) {
    % for addr in sorted(set([r.get_addr() for r in regs if r.is_array])):
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
    case zbx_cpld_field_t::${reg.get_name()}:
        ${reg.get_name()}[idx] = static_cast<${reg.get_type()}>(value);
        break;
        % endfor
    % endfor
    default:
        UHD_ASSERT_THROW(false);
    }
}

uint32_t get_reg(uint16_t addr)
{
    uint32_t reg = 0;
    // First the regular registers
    switch(addr) {
    % for addr in sorted(set([r.get_addr() for r in regs if not r.is_array])):
    case ${addr}:
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
        reg |= (uint32_t(${reg.get_name()}) & ${reg.get_mask()}) << ${reg.get_shift()};
        % endfor
        break;
    % endfor
    default:
        break;
    }
    // Now the arrays
    // We can do this because all arrays have a base address that is a multiple
    // of 256 (0x100). In other words, this is a hack that only works if you
    // know exactly what you're doing, which is OK in this case, because it's in
    // this same file as the register map.
    const uint16_t array_offset = addr % 256;
    const uint16_t base_addr = addr - array_offset;
    const size_t index = array_offset / 4;
    switch(base_addr) {
    % for addr in sorted(set([r.get_addr() for r in regs if r.is_array])):
    case ${addr}:
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
        <% assert reg.get_array_len() == 256, "Arrays must be length 256!" %>
        <% assert reg.get_addr() % 256 == 0, "Arrays must start at a multiple of 0x100!" %>
        reg |= (uint32_t(${reg.get_name()}[index]) & ${reg.get_mask()}) << ${reg.get_shift()};
        % endfor
        break;
    % endfor
    default:
        break;
    }
    return reg;
}

void set_reg(uint16_t addr, uint32_t val)
{
    switch(addr) {
    % for addr in sorted(set([r.get_addr() for r in regs if not r.is_array])):
    case ${addr}:
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
            ${reg.get_name()} = static_cast<${reg.get_type()}>((val & (${reg.get_mask()} << ${reg.get_shift()})) >> ${reg.get_shift()});
        % endfor
        break;
    % endfor
    default:
        break;
    }
    // Now the arrays
    // We can do this because all arrays have a base address that is a multiple
    // of 256 (0x100). In other words, this is a hack that only works if you
    // know exactly what you're doing, which is OK in this case, because it's in
    // this same file as the register map.
    const uint16_t array_offset = addr % 256;
    const uint16_t base_addr = addr - array_offset;
    const size_t index = array_offset / 4;
    switch(base_addr) {
    % for addr in sorted(set([r.get_addr() for r in regs if r.is_array])):
        case ${addr}:
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
            ${reg.get_name()}[index] = static_cast<${reg.get_type()}>((val & (${reg.get_mask()} << ${reg.get_shift()})) >> ${reg.get_shift()});
        % endfor
        break;
    % endfor
        default: break;
    }
}

<%
    all_addrs = set()
    for reg in regs:
        for index in range(reg.get_array_len() if reg.is_array else 1):
            all_addrs.add(reg.get_addr() + index * reg.get_addr_step_size())
%>
std::set<size_t> get_all_addrs()
{
    std::set<size_t> addrs;
    % for addr in sorted(all_addrs):
    addrs.insert(${addr});
    % endfor
    return addrs;
}

uint16_t get_addr(zbx_cpld_field_t field) {
    switch(field) {
    % for addr in sorted(set([r.get_addr() for r in regs if r.is_array])):
        % for reg in filter(lambda r: r.get_addr() == addr, regs):
    case zbx_cpld_field_t::${reg.get_name()}:
        return ${addr};
        % endfor
    % endfor
    default:
        UHD_ASSERT_THROW(false);
        return 0;
    }
}

uint16_t get_addr(const std::string& reg_name)
{
    % for reg in regs:
    if ("${reg.get_name()}" == reg_name) {
        return ${reg.get_addr()};
    }
    % endfor
    return 0;
}
"""

if __name__ == '__main__':
    import common
    common.generate(
        name='zbx_cpld_regs',
        regs_tmpl=REGS_TMPL,
        body_tmpl=BODY_TMPL,
        py_body_tmpl=PY_BODY_TMPL,
        file=__file__,
    )