aboutsummaryrefslogtreecommitdiffstats
path: root/host/utils/rfnoc_blocktool/rfnoc_create_verilog.py
diff options
context:
space:
mode:
authorLars Amsel <lars.amsel@ni.com>2019-04-26 15:51:42 +0200
committerMartin Braun <martin.braun@ettus.com>2019-11-26 11:49:14 -0800
commit752fdd269215a606212fb97e909b08707bf54507 (patch)
treee8fe3eb901e2740641ac34f580f456592286f148 /host/utils/rfnoc_blocktool/rfnoc_create_verilog.py
parent384a94d1b6e3a980c19df70f8a1a95ec9f52eb6e (diff)
downloaduhd-752fdd269215a606212fb97e909b08707bf54507.tar.gz
uhd-752fdd269215a606212fb97e909b08707bf54507.tar.bz2
uhd-752fdd269215a606212fb97e909b08707bf54507.zip
rfnoc: add eRFNoC block builder to generate boiler plate Verilog
This is an initial generator for eRFNoC block. The script generates the top level block, the shell module, a testbench, and a Makefile as well as a Makefile.srcs. To build a block from a yml file one has to invoke python -c <config> -d <destination folder> destination folder should be an in tree module folder located in uhd-fpga/usrp3/lib/erfnoc/blocks The build tool supports all interface types for control as well as data. For each interface type there are three templates to generate the variable block in the top level block and the shell * declare the wires * connect the wires * instantiate the modules The first two are used in the shell module as well as in the top level block. The last is for the shell only.
Diffstat (limited to 'host/utils/rfnoc_blocktool/rfnoc_create_verilog.py')
-rw-r--r--host/utils/rfnoc_blocktool/rfnoc_create_verilog.py131
1 files changed, 131 insertions, 0 deletions
diff --git a/host/utils/rfnoc_blocktool/rfnoc_create_verilog.py b/host/utils/rfnoc_blocktool/rfnoc_create_verilog.py
new file mode 100644
index 000000000..7b4f6cdeb
--- /dev/null
+++ b/host/utils/rfnoc_blocktool/rfnoc_create_verilog.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2013-2015 Ettus Research LLC
+# Copyright 2018 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+"""
+Create a task for each file to generate from templates. A task is based on
+a named tuple to ease future extensions.
+Each task generates on result file by utilizing the BlockGenerator class.
+"""
+
+import argparse
+import datetime
+import os
+import re
+import sys
+from collections import namedtuple
+import six
+import mako.template
+import mako.lookup
+from mako import exceptions
+from ruamel import yaml
+
+
+class BlockGenerator:
+ """
+ Generates a new file from a template utilizing a YAML configuration passed
+ as argument.
+
+ Each BlockGenerator generate one file out of one template.
+ All substitution parameter used in the template must be given in the YAML
+ configuration. Exceptions: year (generated on the fly) and destination
+ (given as argument). The root object parsed from the YAML configuration is
+ config. All configuration items are represented as object members of config
+ (YAML dictionaries are resolved recursively).
+ """
+
+ def __init__(self, template_file):
+ """
+ Initializes a new generator based on template_file
+ :param template_file: file used as root template during rendering,
+ template file is assumed to be located in folder
+ 'modules' relative to this Python file.
+ """
+ self.template_file = template_file
+ self.year = datetime.datetime.now().year
+ self.parser = None
+ self.config = None
+ self.destination = None
+
+ def setup_parser(self):
+ """
+ Setup argument parser.
+
+ ArgumentParser is able to receive destination path and a file location
+ of the YAML configuration.
+ """
+ self.parser = argparse.ArgumentParser(
+ description="Generate RFNoC module out of yml description")
+ self.parser.add_argument("-c", "--config", required=True,
+ help="Path to yml configuration file")
+ self.parser.add_argument("-d", "--destination", required=True,
+ help="Destination path to write output files")
+
+ def setup(self):
+ """
+ Prepare generator for template substitution.
+
+ Results of setup are save in member variables and are accessible for
+ further template processing.
+ self.year current year (for copyright headers)
+ self.destination root path where template generation results are placed
+ self.config everything that was passed as YAML format
+ configuration
+ """
+ args = self.parser.parse_args()
+ self.year = datetime.datetime.now().year
+ self.destination = args.destination
+ os.makedirs(self.destination, exist_ok=True)
+ with open(args.config) as stream:
+ self.config = yaml.safe_load(stream)
+
+ def run(self):
+ """
+ Do template substitution for destination template using YAML
+ configuration passed by arguments.
+
+ Template substitution is done in memory. The result is written to a file
+ where the destination folder is given by the argument parser and the
+ final filename is derived from the template file by substitute template
+ by the module name from the YAML configuration.
+ """
+ lookup = mako.lookup.TemplateLookup(directories=['.'])
+ filename = os.path.join("templates", self.template_file)
+ tpl = mako.template.Template(filename=filename, lookup=lookup,
+ strict_undefined=True)
+ # Render and return
+ try:
+ block = tpl.render(**{"config": self.config,
+ "year": self.year,
+ "destination": self.destination,})
+ except:
+ print(exceptions.text_error_template().render())
+ sys.exit(1)
+
+ filename = self.template_file
+ # pylint: disable=no-member
+ filename = re.sub(r"template(.*)\.mako",
+ r"%s\1" % self.config['module_name'],
+ filename)
+ fullpath = os.path.join(self.destination, filename)
+
+ with open(fullpath, "w") as stream:
+ stream.write(block)
+
+
+if __name__ == "__main__":
+ Task = namedtuple("Task", "name")
+ TASKS = [Task(name="noc_shell_template.v.mako"),
+ Task(name="rfnoc_block_template.v.mako"),
+ Task(name="rfnoc_block_template_tb.sv.mako"),
+ Task(name="Makefile"),
+ Task(name="Makefile.srcs")]
+ for task in TASKS:
+ generator = BlockGenerator(task.name)
+ generator.setup_parser()
+ generator.setup()
+ generator.run()