aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2020-09-30 11:42:44 +0200
committerAaron Rossetto <aaron.rossetto@ni.com>2020-10-06 15:20:37 -0500
commit34733e473ee8364f328dd39b82af6a8e29c56d07 (patch)
tree3de797b2000a65ec98dace8decad52e888bfe173
parentf8674adcd3eb50ba9629726627305235aaa74006 (diff)
downloaduhd-34733e473ee8364f328dd39b82af6a8e29c56d07.tar.gz
uhd-34733e473ee8364f328dd39b82af6a8e29c56d07.tar.bz2
uhd-34733e473ee8364f328dd39b82af6a8e29c56d07.zip
ic_reg_map: Allow registers to be arrays
This lets you declare registers like this: REG_NAME[ARRAY_LEN] ADDRESS[BITS] DEFAULT ENUMS The reg object will now carray REG_NAME as an array. So, you can do regs.REG_NAME[0] = VALUE;
-rwxr-xr-xhost/lib/ic_reg_maps/common.py133
1 files changed, 114 insertions, 19 deletions
diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py
index 46e02094a..96b63410f 100755
--- a/host/lib/ic_reg_maps/common.py
+++ b/host/lib/ic_reg_maps/common.py
@@ -21,25 +21,34 @@ COMMON_TMPL = """<% import time %>\
#include <uhd/config.hpp>
#include <uhd/exception.hpp>
#include <set>
+#include <vector>
#include <stdint.h>
class ${name}_t{
public:
% for reg in regs:
- % if reg.get_enums():
+ % if reg.get_enums():
enum ${reg.get_type()}{
- % for i,enum in enumerate(reg.get_enums()):
+ % for i,enum in enumerate(reg.get_enums()):
${reg.get_name().upper()}_${enum[0].upper()} = ${enum[1]}<% comma = ',' if i != (len(reg.get_enums())-1) else '' %>${comma}
- % endfor
+ % endfor
};
- % endif
+ % endif
+ % if reg.is_array:
+ std::vector<${reg.get_type()}> ${reg.get_name()};
+ % else:
${reg.get_type()} ${reg.get_name()};
+ % endif
% endfor
${name}_t(void){
_state = NULL;
% for reg in regs:
+ % if reg.is_array:
+ ${reg.get_name()}.resize(${reg.get_array_len()}, ${reg.get_default()});
+ % else:
${reg.get_name()} = ${reg.get_default()};
+ % endif
% endfor
}
@@ -61,9 +70,17 @@ public:
//check each register for changes
std::set<T> addrs;
% for reg in regs:
+ % if reg.is_array:
+ for (size_t i = 0; i < ${reg.get_array_len()}; i++) {
+ if(_state->${reg.get_name()}[i] != this->${reg.get_name()}[i]) {
+ addrs.insert(${reg.get_addr()} + i * ${reg.get_addr_step_size()});
+ }
+ }
+ % else:
if(_state->${reg.get_name()} != this->${reg.get_name()}){
addrs.insert(${reg.get_addr()});
}
+ % endif
% endfor
return addrs;
}
@@ -105,7 +122,7 @@ class ${name}_t:
% for reg in regs:
% if reg.get_enums():
class ${reg.get_type()} (Enum):
- % for i,enum in enumerate(reg.get_enums()):
+ % for i, enum in enumerate(reg.get_enums()):
${reg.get_name().upper()}_${enum[0].upper()} = ${enum[1]}
% endfor
% endif
@@ -115,11 +132,19 @@ class ${name}_t:
## Assign each register to its default value
self._state = None
% for reg in regs:
- % if reg.get_enums():
- self.${reg.get_name()} = self.${reg.get_name()}_t.${reg.get_default()}
- % else:
+ % if reg.get_enums():
+ % if reg.is_array:
+ self.${reg.get_name()} = [self.${reg.get_name()}_t.${reg.get_default()},] * ${reg.get_array_len()}
+ % else:
self.${reg.get_name()} = ${reg.get_default()}
- % endif
+ % endif
+ % else:
+ % if reg.is_array:
+ self.${reg.get_name()} = [${reg.get_default()},] * ${reg.get_array_len()}
+ % else:
+ self.${reg.get_name()} = ${reg.get_default()}
+ % endif
+ % endif
self.${reg.get_name()}_addr = ${reg.get_addr()}
self.${reg.get_name()}_mask = ${reg.get_mask()}
self.${reg.get_name()}_shift = ${reg.get_shift()}
@@ -140,8 +165,14 @@ class ${name}_t:
#check each register for changes
addrs = set()
% for reg in regs:
+ % if reg.is_array:
+ for index, value in enumerate(self.${reg.get_name()}):
+ if self._state.${reg.get_name()}[index] != value:
+ addrs.add(${reg.get_addr()} + index * ${reg.get_addr_step_size()})
+ % else:
if self._state.${reg.get_name()} != self.${reg.get_name()}:
addrs.add(${reg.get_addr()})
+ % endif
% endfor
return addrs
@@ -169,25 +200,55 @@ class ${name}_t:
def parse_tmpl(_tmpl_text, **kwargs):
return Template(_tmpl_text).render(**kwargs)
-def to_num(arg): return int(eval(arg))
+def to_num(arg):
+ """
+ Return the integer representation of arg, which is usually a string, but can
+ be a Python representation
+ """
+ return int(eval(arg))
class reg:
def __init__(self, reg_des):
- try: self.parse(reg_des)
+ self.is_array = False
+ self._array_len = 0
+ self._addr_step = 0
+ try:
+ self.parse(reg_des)
except Exception as e:
- raise Exception('Error parsing register description: "%s"\nWhat: %s'%(reg_des, e))
+ raise Exception(
+ 'Error parsing register description: "{}"\nWhat: {}'
+ .format(reg_des, e))
def parse(self, reg_des):
- x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des)
- name, addr, bit_range, default, enums = x.groups()
+ """
+ Parse a regmap line.
+
+ Unpacks lines like this:
+ REG_NAME[ARRAY_LEN] BASE_ADDRESS[BITS] DEFAULT LIST_OF_ENUMS
+
+ Notes:
+ - Array length and enums are optional
+ - Base address == address if not an array
+
+ Example:
+
+ super_reg 0x1000[0:1] 0
+ duper_reg[128] 0x2000[0:31] 0
+
+ super_reg is a 2-bit field in register at address 0x1000. It will be
+ 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*(.*)$',
+ reg_des)
+ name, _, addr_range, addr, bit_range, default, 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)
-
#extract enum
self._enums = list()
if enums:
@@ -200,8 +261,27 @@ class reg:
else: enum_name = enum_str
self._enums.append((enum_name, enum_val))
enum_val += 1
+ # Extract address range for arrays
+ if addr_range is not None:
+ self.is_array = True
+ addr_range = addr_range.split(':', 3)
+ if len(addr_range) == 1:
+ self._array_len = to_num(addr_range[0])
+ self._addr_step = 4
+ else:
+ addr_start = to_num(addr_range[0])
+ addr_end = to_num(addr_range[1])
+ self._array_len = addr_end - addr_start + 1
+ self._addr_step = 4 if len(addr_range) == 2 else to_num(addr_range[2])
+ if addr_start > 0:
+ self._addr += addr_start
+
+ def get_addr(self):
+ """
+ Return register address. If it's an array, then return the base address.
+ """
+ return self._addr
- def get_addr(self): return self._addr
def get_enums(self): return self._enums
def get_name(self): return self._name
def get_default(self):
@@ -215,6 +295,18 @@ class reg:
def get_mask(self): return hex(int('1'*self.get_bit_width(), 2))
def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1
+ def get_array_len(self):
+ """
+ Return 1 for regular registers, or the array length for arrays
+ """
+ return self._array_len
+
+ def get_addr_step_size(self):
+ """
+ Return the step size for register arrays
+ """
+ return self._addr_step
+
class mreg:
def __init__(self, mreg_des, regs):
try: self.parse(mreg_des, regs)
@@ -244,10 +336,13 @@ def generate(name, regs_tmpl, body_tmpl='', py_body_tmpl='', file=__file__, appe
body_template = body_tmpl
#evaluate the regs template and parse each line into a register
- regs = list(); mregs = list()
+ regs = list()
+ mregs = list()
for entry in parse_tmpl(regs_tmpl).splitlines():
- if entry.startswith('~'): mregs.append(mreg(entry, regs))
- else: regs.append(reg(entry))
+ if entry.startswith('~'):
+ mregs.append(mreg(entry, regs))
+ else:
+ regs.append(reg(entry))
#evaluate the body template with the list of registers
body = '\n '.join(parse_tmpl(body_template, regs=regs).splitlines())