diff options
author | Lars Amsel <lars.amsel@ni.com> | 2022-04-07 18:32:22 +0200 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2022-06-10 13:24:04 -0500 |
commit | 9fb6b67f29d479da2c78814e8e3c90b0a192b508 (patch) | |
tree | b78d0409b1a9935e29b6555e72d74f9a981e8f6c | |
parent | 91de4116d8f7c01db36095f46f040e6e9bf815dc (diff) | |
download | uhd-9fb6b67f29d479da2c78814e8e3c90b0a192b508.tar.gz uhd-9fb6b67f29d479da2c78814e8e3c90b0a192b508.tar.bz2 uhd-9fb6b67f29d479da2c78814e8e3c90b0a192b508.zip |
uhd: change default into option flag in register definition
This adds support for read only registers in generated interfaces.
For this the default is extended to an option string. The old format
is still supported for backward compability, so if options string is
just a number it will be handled as a writable number.
The option string is a comma separated list with key=value pairs. The
value is optional and treated as None if missing.
common.py now allows to pass in **kwargs to the generate method which
is used by gen_zbx_cpld_regs.py to pass a filter function for registers
used by mpm only.
get_all_addr now has an additional (optional, defaults to false) flag
to indicate whether read only addresses are to be returned or not.
It also supports type generic for the result to align with
get_changed_addr function.
The ZBX CPLD CTRL map is adapted accordingly to reflect read only
registers. The power registers are flagged as MPM scope only (and not
used in ZBX CPLD control of UHD).
Co-authored-by: Martin Braun <martin.braun@ettus.com>
-rwxr-xr-x | host/lib/ic_reg_maps/common.py | 50 | ||||
-rwxr-xr-x | host/lib/ic_reg_maps/gen_zbx_cpld_regs.py | 63 | ||||
-rw-r--r-- | host/lib/usrp/dboard/zbx/zbx_cpld_ctrl.cpp | 2 |
3 files changed, 80 insertions, 35 deletions
diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py index a689872ff..2275c68e2 100755 --- a/host/lib/ic_reg_maps/common.py +++ b/host/lib/ic_reg_maps/common.py @@ -235,6 +235,18 @@ def to_num(arg): """ return int(eval(arg)) +def is_int(arg): + """ + check whether arg is convertable to an integer + (including non-decimal representation) + """ + try: + to_num(arg) + return True + except: + return False + + class reg: def __init__(self, reg_des): self.is_array = False @@ -247,6 +259,22 @@ class reg: 'Error parsing register description: "{}"\nWhat: {}' .format(reg_des, e)) + def _parse_options(self, optionstr): + """ + `optionstr` contains additional register information in a + comma-separated list as key=value pairs. + + For backward compability a number <x> is converted to + `default=<x>,rw` + which retains the previous behaviour. + """ + if is_int(optionstr): + # convert number into option list for backward compability + optionstr = f"default={optionstr},rw" + options = [option.partition("=") for option in optionstr.split(",")] + result = { item[0] : item[2] or None for item in options } + return result + def parse(self, reg_des): """ Parse a regmap line. @@ -268,15 +296,15 @@ class reg: initialized to 0. duper_reg is an array of length 128, of 32-bit registers. """ x = re.match( - r'^(\w*)(\[([0-9:]*)\])?\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', + r'^(\w*)(\[([0-9:]*)\])?\s*(\w*)\[(.*)\]\s*([=,\w]*)\s*(.*)$', reg_des) - name, _, addr_range, addr, bit_range, default, enums = x.groups() + name, _, addr_range, addr, bit_range, options, enums = x.groups() #store variables self._name = name self._addr = to_num(addr) if ':' in bit_range: self._addr_spec = sorted(map(int, bit_range.split(':'))) else: self._addr_spec = int(bit_range), int(bit_range) - self._default = to_num(default) + self.options = self._parse_options(options) #extract enum self._enums = list() if enums: @@ -313,9 +341,10 @@ class reg: def get_enums(self): return self._enums def get_name(self): return self._name def get_default(self): + default_val = to_num(self.options.get("default", "0")) for key, val in self.get_enums(): - if val == self._default: return ('%s_%s'%(self.get_name(), key)).upper() - return self._default + if val == default_val: return ('%s_%s'%(self.get_name(), key)).upper() + return default_val def get_type(self): if self.get_enums(): return '%s_t'%self.get_name() return 'uint%d_t'%max(2**math.ceil(math.log(self.get_bit_width(), 2)), 8) @@ -334,6 +363,11 @@ class reg: Return the step size for register arrays """ return self._addr_step + def is_readonly(self): + """ + Check whether register is marked as readonly via option string + """ + return "ro" in self.options class mreg: def __init__(self, mreg_des, regs): @@ -353,7 +387,7 @@ class mreg: def get_type(self): return 'uint%d_t'%max(2**math.ceil(math.log(self.get_bit_width(), 2)), 8) -def generate(name, regs_tmpl, body_tmpl='', py_body_tmpl='', file=__file__, append=False): +def generate(name, regs_tmpl, body_tmpl='', py_body_tmpl='', file=__file__, append=False, **kwargs): # determine if the destination file is a Python or C++ header file out_file = sys.argv[1] if out_file.endswith('.py'): # Write a Python file @@ -373,15 +407,17 @@ def generate(name, regs_tmpl, body_tmpl='', py_body_tmpl='', file=__file__, appe regs.append(reg(entry)) #evaluate the body template with the list of registers - body = '\n '.join(parse_tmpl(body_template, regs=regs).splitlines()) + body = '\n '.join(parse_tmpl(body_template, **dict(kwargs, regs=regs)).splitlines()) #evaluate the code template with the parsed registers and arguments code = parse_tmpl(template, + **dict(kwargs, name=name, regs=regs, mregs=mregs, body=body, file=file, + ) ) #write the generated code to file specified by argv1 diff --git a/host/lib/ic_reg_maps/gen_zbx_cpld_regs.py b/host/lib/ic_reg_maps/gen_zbx_cpld_regs.py index 0efc8a4d7..fce051d53 100755 --- a/host/lib/ic_reg_maps/gen_zbx_cpld_regs.py +++ b/host/lib/ic_reg_maps/gen_zbx_cpld_regs.py @@ -18,24 +18,24 @@ REGS_TMPL = """\ ######################################################################## ## SLAVE SETUP ######################################################################## -BOARD_ID 0x0000[0:15] 0 -REVISION 0x0004[0:31] 0 -OLDEST_COMPAT_REVISION 0x0008[0:31] 0 +BOARD_ID 0x0000[0:15] ro +REVISION 0x0004[0:31] ro +OLDEST_COMPAT_REVISION 0x0008[0:31] ro 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 +GIT_HASH 0x0010[0:31] ro +ENABLE_TX_POS_7V0 0x0040[0] scope=mpm disable, enable +ENABLE_RX_POS_7V0 0x0040[1] scope=mpm disable, enable +ENABLE_POS_3V3 0x0040[2] scope=mpm disable, enable +P7V_B_STATUS 0x0044[0] scope=mpm,ro +P7V_A_STATUS 0x0044[1] scope=mpm,ro +PLL_REF_CLOCK_ENABLE 0x0048[0] scope=mpm 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 +CURRENT_RF0_CONFIG 0x1000[0:7] ro +CURRENT_RF1_CONFIG 0x1000[8:15] ro +CURRENT_RF0_DSA_CONFIG 0x1000[23:16] ro +CURRENT_RF1_DSA_CONFIG 0x1000[31:24] ro 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 @@ -52,8 +52,8 @@ 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 +SPI_READY 0x1020[30] ro +DATA_VALID 0x1020[31] ro ######################################################################## ## LO SYNC ######################################################################## @@ -301,7 +301,7 @@ uint32_t get_field(zbx_cpld_field_t field, const size_t idx) { 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): + % for reg in filter(lambda r: r.get_addr() == addr and not r.is_readonly(), regs): case zbx_cpld_field_t::${reg.get_name()}: ${reg.get_name()} = static_cast<${reg.get_type()}>(value); break; @@ -399,17 +399,19 @@ void set_reg(uint16_t addr, uint32_t val) } } -<% - 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() +template<typename T> std::set<T> get_all_addrs(bool include_ro = false) { - std::set<size_t> addrs; - % for addr in sorted(all_addrs): - addrs.insert(${addr}); + std::set<T> addrs; + % for reg in filter(all_addr_filter, regs): + % if reg.is_readonly(): + if (include_ro) { + % else: + { + % endif + % for index in range(reg.get_array_len() if reg.is_array else 1): + addrs.insert(${reg.get_addr() + index * reg.get_addr_step_size()}); + % endfor + } % endfor return addrs; } @@ -440,11 +442,18 @@ uint16_t get_addr(const std::string& reg_name) """ if __name__ == '__main__': + import sys import common + outfile=sys.argv[1] + if outfile.endswith(".hpp"): + all_addr_filter = lambda reg: "mpm" not in reg.options.get("scope", "") + else: + all_addr_filter = lambda reg: True common.generate( name='zbx_cpld_regs', regs_tmpl=REGS_TMPL, body_tmpl=BODY_TMPL, py_body_tmpl=PY_BODY_TMPL, file=__file__, + all_addr_filter=all_addr_filter ) diff --git a/host/lib/usrp/dboard/zbx/zbx_cpld_ctrl.cpp b/host/lib/usrp/dboard/zbx/zbx_cpld_ctrl.cpp index 352a7def9..28a7c6347 100644 --- a/host/lib/usrp/dboard/zbx/zbx_cpld_ctrl.cpp +++ b/host/lib/usrp/dboard/zbx/zbx_cpld_ctrl.cpp @@ -900,7 +900,7 @@ void zbx_cpld_ctrl::commit(const chan_t chan, const bool save_all) UHD_LOG_TRACE(_log_id, "Storing register cache " << (save_all ? "completely" : "selectively") << " to CPLD..."); - const auto changed_addrs = save_all ? _regs.get_all_addrs() + const auto changed_addrs = save_all ? _regs.get_all_addrs<size_t>() : _regs.get_changed_addrs<size_t>(); for (const auto addr : changed_addrs) { _poke32(addr, _regs.get_reg(addr), save_all ? NO_CHAN : chan); |