aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Rossetto <aaron.rossetto@ni.com>2020-06-10 07:45:40 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2020-06-18 09:54:22 -0500
commitade5e6d57ed00641782595cc574297ab1b235f08 (patch)
treefcb47757ee44f6dd5507a7f2d51eedf7c67a998a
parent3af8dcaacfa4bf36dcae3bdbf0b353385b7063c6 (diff)
downloaduhd-ade5e6d57ed00641782595cc574297ab1b235f08.tar.gz
uhd-ade5e6d57ed00641782595cc574297ab1b235f08.tar.bz2
uhd-ade5e6d57ed00641782595cc574297ab1b235f08.zip
utils: Support expressions for num_ports in block defs
This commit allows the RFNoC image builder utility to support block definition .yml files where the num_ports values are numerical expressions using values sourced from the parameters section when the block is used in an RFNoC image. An example of such an expression for num_ports is the split stream block, where the number of output ports is defined as the product of the NUM_PORTS and NUM_BRANCHES parameters: data: fpga_iface: axis_chdr clk_domain: rfnoc_chdr inputs: in: num_ports: NUM_PORTS outputs: out: num_ports: NUM_PORTS*NUM_BRANCHES In an RFNoC image definition .yml file, these parameters can be specified when a split stream block is instantiated in an image: split0: block_desc: 'split_stream.yml' parameters: NUM_PORTS: 2 NUM_BRANCHES: 3 Thus, the split0 instance of the split stream block is configured with 2 input ports and 6 output ports (2*3 from NUM_PORTS*NUM_BRANCHES). When the RFNoC image builder runs and encounters a block instantiation where that block has a non-integer string in the num_ports key of its block definition, it performs a textual replacement of the identifiers in the string with the corresponding values from the parameters section of the block's instantiation. If no such parameter corresponding to the identifier exists, the block definition file's parameters section is consulted for a default value for the parameter. If no such parameter can be found in either of these locations, the identifier is left unchanged in place. After the text substitution step, the expression is evaluated using Python's expression evaluator. The expression should evaluate to an integer value, which is then used as the num_ports value. If the expression does not evaluate to an integer, or fails to evaluate, an error will be reported.
-rwxr-xr-xhost/python/uhd/imgbuilder/image_builder.py38
1 files changed, 36 insertions, 2 deletions
diff --git a/host/python/uhd/imgbuilder/image_builder.py b/host/python/uhd/imgbuilder/image_builder.py
index 995e26047..fba87361b 100755
--- a/host/python/uhd/imgbuilder/image_builder.py
+++ b/host/python/uhd/imgbuilder/image_builder.py
@@ -235,8 +235,42 @@ class ImageBuilderConfig:
if "num_ports" in port_info:
parameter = port_info["num_ports"]
num_ports = parameter
- if parameter in block["parameters"]:
- num_ports = block["parameters"][parameter]
+
+ # If num_ports isn't an integer, it could be an expression
+ # using values from the parameters section (e.g.,
+ # NUM_PORTS*NUM_BRANCHES for a stream-splitting block).
+ # If the parameter doesn't resolve to an integer, treat it
+ # as an expression that needs to be evaluated, hopefully to
+ # an integer.
+ if not isinstance(num_ports, int):
+ # Create a regex to find identifiers.
+ regex_ident = re.compile(r'[A-Za-z_][A-Za-z0-9_]*')
+
+ # Get a list of all identifiers in the num_ports
+ # expression and iterate over them all
+ idents = re.finditer(regex_ident, num_ports)
+ for ident in idents:
+ # If the identifier represents a valid parameter
+ # in the block, replace the identifier text with
+ # the value of the parameter. If no matching
+ # parameter is found, just leave the text in
+ # place. That may result in an exception being
+ # thrown from eval(), but we'll catch it and
+ # report an error a bit later on.
+ if ident[0] in block["parameters"]:
+ val = str(block["parameters"][ident[0]])
+ num_ports = re.sub(ident[0], val, num_ports)
+
+ # Now, with identifiers resolved to parameter values,
+ # attempt to evaluate the expression. If eval() fails,
+ # we'll catch the exception, num_ports will remain non-
+ # integral, and the if statement after the exception
+ # is caught will inform the user.
+ try:
+ num_ports = eval(num_ports)
+ except:
+ pass
+
# Make sure the parameter resolved to a number
if not isinstance(num_ports, int):
logging.error(