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 /host/lib/ic_reg_maps/common.py | |
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>
Diffstat (limited to 'host/lib/ic_reg_maps/common.py')
-rwxr-xr-x | host/lib/ic_reg_maps/common.py | 50 |
1 files changed, 43 insertions, 7 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 |