diff options
author | Lars Amsel <lars.amsel@ni.com> | 2019-04-26 15:51:42 +0200 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 11:49:14 -0800 |
commit | 752fdd269215a606212fb97e909b08707bf54507 (patch) | |
tree | e8fe3eb901e2740641ac34f580f456592286f148 /host/utils/rfnoc_blocktool | |
parent | 384a94d1b6e3a980c19df70f8a1a95ec9f52eb6e (diff) | |
download | uhd-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')
18 files changed, 1069 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() diff --git a/host/utils/rfnoc_blocktool/templates/Makefile b/host/utils/rfnoc_blocktool/templates/Makefile new file mode 100644 index 000000000..25e61c05b --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/Makefile @@ -0,0 +1,48 @@ +# +# Copyright 2019 Ettus Research, A National Instruments Company +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir +BASE_DIR = $(abspath ../../../../top) +# Include viv_sim_preample after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +# Include makefiles and sources for the DUT and its dependencies +include $(BASE_DIR)/../lib/erfnoc/core/Makefile.srcs +include $(BASE_DIR)/../lib/erfnoc/utils/Makefile.srcs +include Makefile.srcs + +DESIGN_SRCS += $(abspath ${"\\"} +$(RFNOC_CORE_SRCS) ${"\\"} +$(RFNOC_UTIL_SRCS) ${"\\"} +$(RFNOC_BLOCK_${config.module_name.upper()}_SRCS) ${"\\"} +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +include $(BASE_DIR)/../sim/erfnoc/Makefile.srcs + +SIM_TOP = rfnoc_block_${config.module_name}_tb + +SIM_SRCS = ${"\\"} +$(abspath rfnoc_block_${config.module_name}_tb.sv) ${"\\"} +$(SIM_ERFNOC_SRCS) + +# MODELSIM_USER_DO = $(abspath wave.do) + +#------------------------------------------------- +# Bottom-of-Makefile +#------------------------------------------------- +# Include all simulator specific makefiles here +# Each should define a unique target to simulate +# e.g. xsim, vsim, etc and a common "clean" target +include $(BASE_DIR)/../tools/make/viv_simulator.mak diff --git a/host/utils/rfnoc_blocktool/templates/Makefile.srcs b/host/utils/rfnoc_blocktool/templates/Makefile.srcs new file mode 100644 index 000000000..f346007af --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/Makefile.srcs @@ -0,0 +1,13 @@ +# +# Copyright 2018 Ettus Research, A National Instruments Company +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +${'##################################################'} +# RFNoC Utility Sources +${'##################################################'} +RFNOC_BLOCK_${config.module_name.upper()}_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/erfnoc/blocks/${destination}/, ${"\\"} +rfnoc_block_${config.module_name}.v ${"\\"} +noc_shell_${config.module_name}.v ${"\\"} +)) diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_connect_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_connect_template.mako new file mode 100644 index 000000000..ff619b6d9 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_connect_template.mako @@ -0,0 +1,15 @@ +<%page args="num_inputs, num_outputs"/> + +%for idx, input in enumerate(config['data']['inputs']): + .m_${input}_chdr_tdata(${input}_chdr_tdata), + .m_${input}_chdr_tlast(${input}_chdr_tlast), + .m_${input}_chdr_tvalid(${input}_chdr_tvalid), + .m_${input}_chdr_tready(${input}_chdr_tready)${"," if (idx < num_inputs -1) or (num_outputs > 0) else ""} +%endfor + +%for idx, output in enumerate(config['data']['outputs']): + .s_${output}_chdr_tdata(${output}_chdr_tdata), + .s_${output}_chdr_tlast(${output}_chdr_tlast), + .s_${output}_chdr_tvalid(${output}_chdr_tvalid), + .s_${output}_chdr_tready(${output}_chdr_tready)${"," if (idx < num_outputs -1) else ""} +%endfor diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_modules_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_modules_template.mako new file mode 100644 index 000000000..bcb23dff6 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_modules_template.mako @@ -0,0 +1,41 @@ +%for idx, input in enumerate(config['data']['inputs']): + chdr_to_chdr_data #( + .CHDR_W(CHDR_W) + ) chdr_to_chdr_data_i${idx} ( + .axis_chdr_clk(rfnoc_chdr_clk), + .axis_chdr_rst(rfnoc_chdr_rst), + .s_axis_chdr_tdata(s_rfnoc_chdr_tdata[(${idx}*CHDR_W)+:CHDR_W]), + .s_axis_chdr_tlast(s_rfnoc_chdr_tlast[${idx}]), + .s_axis_chdr_tvalid(s_rfnoc_chdr_tvalid[${idx}]), + .s_axis_chdr_tready(s_rfnoc_chdr_tready[${idx}]), + .m_axis_chdr_tdata(m_${input}_chdr_tdata), + .m_axis_chdr_tlast(m_${input}_chdr_tlast), + .m_axis_chdr_tvalid(m_${input}_chdr_tvalid), + .m_axis_chdr_tready(m_${input}_chdr_tready), + .flush_en(data_i_flush_en), + .flush_timeout(data_i_flush_timeout), + .flush_active(data_i_flush_active[${idx}]), + .flush_done(data_i_flush_done[${idx}]) + ); +%endfor + +%for idx, output in enumerate(config['data']['outputs']): + chdr_to_chdr_data #( + .CHDR_W(CHDR_W) + ) chdr_to_chdr_data_o${idx} ( + .axis_chdr_clk(rfnoc_chdr_clk), + .axis_chdr_rst(rfnoc_chdr_rst), + .m_axis_chdr_tdata(m_rfnoc_chdr_tdata[(${idx}*CHDR_W)+:CHDR_W]), + .m_axis_chdr_tlast(m_rfnoc_chdr_tlast[${idx}]), + .m_axis_chdr_tvalid(m_rfnoc_chdr_tvalid[${idx}]), + .m_axis_chdr_tready(m_rfnoc_chdr_tready[${idx}]), + .s_axis_chdr_tdata(s_${output}_chdr_tdata), + .s_axis_chdr_tlast(s_${output}_chdr_tlast), + .s_axis_chdr_tvalid(s_${output}_chdr_tvalid), + .s_axis_chdr_tready(s_${output}_chdr_tready), + .flush_en(data_o_flush_en), + .flush_timeout(data_o_flush_timeout), + .flush_active(data_o_flush_active[${idx}]), + .flush_done(data_o_flush_done[${idx}]) + ); +%endfor diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_wires_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_wires_template.mako new file mode 100644 index 000000000..9453c8fd1 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_chdr_wires_template.mako @@ -0,0 +1,30 @@ +<%page args="mode, num_inputs, num_outputs"/>\ + +<% + if mode == "shell": + sl_pre = "s_" + ma_pre = "m_" + in_wire = "input " + out_wire = "output " + term = "," + elif mode == "block": + sl_pre = "" + ma_pre = "" + in_wire = "" + out_wire = "" + term=";" +%>\ +%for idx, port in enumerate(config['data']['inputs']): + // Payload Stream to User Logic: ${port} + ${out_wire}wire [CHDR_W-1:0] ${ma_pre}${port}_chdr_tdata${term} + ${out_wire}wire ${ma_pre}${port}_chdr_tlast${term} + ${out_wire}wire ${ma_pre}${port}_chdr_tvalid${term} + ${in_wire}wire ${ma_pre}${port}_chdr_tready${term if (term == ";") or (idx < num_inputs -1) or (num_outputs > 0) else ""} +%endfor + +%for idx, port in enumerate(config['data']['outputs']): + ${in_wire}wire [CHDR_W-1:0] ${sl_pre}${port}_chdr_tdata${term} + ${in_wire}wire ${sl_pre}${port}_chdr_tlast${term} + ${in_wire}wire ${sl_pre}${port}_chdr_tvalid${term} + ${out_wire}wire ${sl_pre}${port}_chdr_tready${term if (term == ";") or (idx < num_outputs -1) else ""} +%endfor diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_connect_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_connect_template.mako new file mode 100644 index 000000000..cefc97a22 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_connect_template.mako @@ -0,0 +1,8 @@ + .m_axis_ctrl_tdata(m_axis_ctrl_tdata), + .m_axis_ctrl_tlast(m_axis_ctrl_tlast), + .m_axis_ctrl_tvalid(m_axis_ctrl_tvalid), + .m_axis_ctrl_tready(m_axis_ctrl_tready), + .s_axis_ctrl_tdata(s_axis_ctrl_tdata), + .s_axis_ctrl_tlast(s_axis_ctrl_tlast), + .s_axis_ctrl_tvalid(s_axis_ctrl_tvalid), + .s_axis_ctrl_tready(s_axis_ctrl_tready), diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_modules_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_modules_template.mako new file mode 100644 index 000000000..4c349b11b --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_modules_template.mako @@ -0,0 +1,28 @@ +<%! +import math +%> + axis_ctrl_endpoint #( + .SYNC_CLKS(${1 if config['control']['clk_domain'] == "rfnoc_ctrl" else 0}), + .SLAVE_FIFO_SIZE(${math.ceil(math.log2(config['control']['fifo_depth']))}) + ) axis_ctrl_endpoint_i ( + .rfnoc_ctrl_clk(rfnoc_ctrl_clk), + .rfnoc_ctrl_rst(rfnoc_ctrl_rst), + .axis_ctrl_clk(axis_ctrl_clk), + .axis_ctrl_rst(axis_ctrl_rst), + .s_rfnoc_ctrl_tdata(s_rfnoc_ctrl_tdata), + .s_rfnoc_ctrl_tlast(s_rfnoc_ctrl_tlast), + .s_rfnoc_ctrl_tvalid(s_rfnoc_ctrl_tvalid), + .s_rfnoc_ctrl_tready(s_rfnoc_ctrl_tready), + .m_rfnoc_ctrl_tdata(m_rfnoc_ctrl_tdata), + .m_rfnoc_ctrl_tlast(m_rfnoc_ctrl_tlast), + .m_rfnoc_ctrl_tvalid(m_rfnoc_ctrl_tvalid), + .m_rfnoc_ctrl_tready(m_rfnoc_ctrl_tready), + .s_axis_ctrl_tdata(s_axis_ctrl_tdata), + .s_axis_ctrl_tlast(s_axis_ctrl_tlast), + .s_axis_ctrl_tvalid(s_axis_ctrl_tvalid), + .s_axis_ctrl_tready(s_axis_ctrl_tready), + .m_axis_ctrl_tdata(m_axis_ctrl_tdata), + .m_axis_ctrl_tlast(m_axis_ctrl_tlast), + .m_axis_ctrl_tvalid(m_axis_ctrl_tvalid), + .m_axis_ctrl_tready(m_axis_ctrl_tready) + ); diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_wires_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_wires_template.mako new file mode 100644 index 000000000..dd15bd100 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_ctrl_wires_template.mako @@ -0,0 +1,23 @@ +<%page args="mode"/>\ +<% + if mode == "shell": + sl_pre = "s_" + ma_pre = "m_" + in_wire = "input " + out_wire = "output " + term = "," + elif mode == "block": + sl_pre = "s_" + ma_pre = "m_" + in_wire = "" + out_wire = "" + term = ";" +%>\ + ${out_wire}wire [31:0] ${ma_pre}axis_ctrl_tdata${term} + ${out_wire}wire ${ma_pre}axis_ctrl_tlast${term} + ${out_wire}wire ${ma_pre}axis_ctrl_tvalid${term} + ${in_wire}wire ${ma_pre}axis_ctrl_tready${term} + ${in_wire}wire [31:0] ${sl_pre}axis_ctrl_tdata${term} + ${in_wire}wire ${sl_pre}axis_ctrl_tlast${term} + ${in_wire}wire ${sl_pre}axis_ctrl_tvalid${term} + ${out_wire}wire ${sl_pre}axis_ctrl_tready${term} diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_raw_connect_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_raw_connect_template.mako new file mode 100644 index 000000000..c78946289 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_raw_connect_template.mako @@ -0,0 +1,31 @@ +<%page args="num_inputs, num_outputs"/>\ +\ +%for idx, input in enumerate(config['data']['inputs']): + // Payload Stream to User Logic: ${input} + .m_${input}_payload_tdata(${input}_payload_tdata), + .m_${input}_payload_tkeep(${input}_payload_tkeep), + .m_${input}_payload_tlast(${input}_payload_tlast), + .m_${input}_payload_tvalid(${input}_payload_tvalid), + .m_${input}_payload_tready(${input}_payload_tready), + // Context Stream to User Logic: ${input} + .m_${input}_context_tdata(${input}_context_tdata), + .m_${input}_context_tuser(${input}_context_tuser), + .m_${input}_context_tlast(${input}_context_tlast), + .m_${input}_context_tvalid(${input}_context_tvalid), + .m_${input}_context_tready(${input}_context_tready)${"," if (idx < num_inputs - 1) or (num_outputs > 0) else ""} +%endfor + +%for idx, output in enumerate(config['data']['outputs']): + // Payload Stream from User Logic: ${output} + .s_${output}_payload_tdata(${output}_payload_tdata), + .s_${output}_payload_tkeep(${output}_payload_tkeep), + .s_${output}_payload_tlast(${output}_payload_tlast), + .s_${output}_payload_tvalid(${output}_payload_tvalid), + .s_${output}_payload_tready(${output}_payload_tready), + // Context Stream from User Logic: ${output} + .s_${output}_context_tdata(${output}_context_tdata), + .s_${output}_context_tuser(${output}_context_tuser), + .s_${output}_context_tlast(${output}_context_tlast), + .s_${output}_context_tvalid(${output}_context_tvalid), + .s_${output}_context_tready(${output}_context_tready)${"," if (idx < num_outputs -1) else ""} +%endfor diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_raw_modules_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_raw_modules_template.mako new file mode 100644 index 000000000..c181eeedd --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_raw_modules_template.mako @@ -0,0 +1,78 @@ + +%for idx, input in enumerate(config['data']['inputs']): + <% + port_tmp = config['data']['inputs'][input] + %> + chdr_to_axis_raw_data #( + .CHDR_W(CHDR_W), + .ITEM_W(${port_tmp['item_width']}), + .NIPC(${port_tmp['nipc']}), + .SYNC_CLKS(${1 if config['data']['clk_domain'] == "rfnoc_chdr" else 0}), + .CONTEXT_FIFO_SIZE(${port_tmp['context_fifo_depth']}), + .PAYLOAD_FIFO_SIZE(${port_tmp['payload_fifo_depth']}), + .CONTEXT_PREFETCH_EN(1) + ) chdr_to_axis_raw_data_i${idx} ( + .axis_chdr_clk(rfnoc_chdr_clk), + .axis_chdr_rst(rfnoc_chdr_rst), + .axis_data_clk(axis_data_clk), + .axis_data_rst(axis_data_rst), + .s_axis_chdr_tdata(s_rfnoc_chdr_tdata[(${idx}*CHDR_W)+:CHDR_W]), + .s_axis_chdr_tlast(s_rfnoc_chdr_tlast[${idx}]), + .s_axis_chdr_tvalid(s_rfnoc_chdr_tvalid[${idx}]), + .s_axis_chdr_tready(s_rfnoc_chdr_tready[${idx}]), + .m_axis_payload_tdata(m_${input}_payload_tdata), + .m_axis_payload_tkeep(m_${input}_payload_tkeep), + .m_axis_payload_tlast(m_${input}_payload_tlast), + .m_axis_payload_tvalid(m_${input}_payload_tvalid), + .m_axis_payload_tready(m_${input}_payload_tready), + .m_axis_context_tdata(m_${input}_context_tdata), + .m_axis_context_tuser(m_${input}_context_tuser), + .m_axis_context_tlast(m_${input}_context_tlast), + .m_axis_context_tvalid(m_${input}_context_tvalid), + .m_axis_context_tready(m_${input}_context_tready), + .flush_en(data_i_flush_en), + .flush_timeout(data_i_flush_timeout), + .flush_active(data_i_flush_active[${idx}]), + .flush_done(data_i_flush_done[${idx}]) + ); +%endfor + +%for idx, output in enumerate(config['data']['outputs']): + <% + port_tmp = config['data']['outputs'][output] + %> + axis_raw_data_to_chdr #( + .CHDR_W(CHDR_W), + .ITEM_W(${port_tmp['item_width']}), + .NIPC(${port_tmp['nipc']}), + .SYNC_CLKS(${1 if config['data']['clk_domain'] == "rfnoc_chdr" else 0}), + .CONTEXT_FIFO_SIZE(${port_tmp['context_fifo_depth']}), + .PAYLOAD_FIFO_SIZE(${port_tmp['payload_fifo_depth']}), + .CONTEXT_PREFETCH_EN(1), + .MTU(MTU) + ) axis_raw_data_to_chdr_i${idx} ( + .axis_chdr_clk(rfnoc_chdr_clk), + .axis_chdr_rst(rfnoc_chdr_rst), + .axis_data_clk(axis_data_clk), + .axis_data_rst(axis_data_rst), + .m_axis_chdr_tdata(m_rfnoc_chdr_tdata[(${idx}*CHDR_W)+:CHDR_W]), + .m_axis_chdr_tlast(m_rfnoc_chdr_tlast[${idx}]), + .m_axis_chdr_tvalid(m_rfnoc_chdr_tvalid[${idx}]), + .m_axis_chdr_tready(m_rfnoc_chdr_tready[${idx}]), + .s_axis_payload_tdata(s_${output}_payload_tdata), + .s_axis_payload_tkeep(s_${output}_payload_tkeep), + .s_axis_payload_tlast(s_${output}_payload_tlast), + .s_axis_payload_tvalid(s_${output}_payload_tvalid), + .s_axis_payload_tready(s_${output}_payload_tready), + .s_axis_context_tdata(s_${output}_context_tdata), + .s_axis_context_tuser(s_${output}_context_tuser), + .s_axis_context_tlast(s_${output}_context_tlast), + .s_axis_context_tvalid(s_${output}_context_tvalid), + .s_axis_context_tready(s_${output}_context_tready), + .framer_errors(), + .flush_en(data_o_flush_en), + .flush_timeout(data_o_flush_timeout), + .flush_active(data_o_flush_active[${idx}]), + .flush_done(data_o_flush_done[${idx}]) + ); +%endfor diff --git a/host/utils/rfnoc_blocktool/templates/modules/axis_raw_wires_template.mako b/host/utils/rfnoc_blocktool/templates/modules/axis_raw_wires_template.mako new file mode 100644 index 000000000..abb8ef5e0 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/axis_raw_wires_template.mako @@ -0,0 +1,50 @@ +<%page args="mode, num_inputs, num_outputs"/>\ +<% + if mode == "shell": + sl_pre = "s_" + ma_pre = "m_" + in_wire = "input " + out_wire = "output " + term = "," + elif mode == "block": + sl_pre = "" + ma_pre = "" + in_wire = "" + out_wire = "" + term = ";" +%>\ +%for idx, port in enumerate(config['data']['inputs']): + <% + port_tmp = config['data']['inputs'][port] + %>\ + // Payload Stream to User Logic: ${port} + ${out_wire}wire [${port_tmp['item_width']*port_tmp['nipc']-1}:0] ${ma_pre}${port}_payload_tdata${term} + ${out_wire}wire [${port_tmp['nipc']-1}:0] ${ma_pre}${port}_payload_tkeep${term} + ${out_wire}wire ${ma_pre}${port}_payload_tlast${term} + ${out_wire}wire ${ma_pre}${port}_payload_tvalid${term} + ${in_wire}wire ${ma_pre}${port}_payload_tready${term} + // Context Stream to User Logic: ${port} + ${out_wire}wire [CHDR_W-1:0] ${ma_pre}${port}_context_tdata${term} + ${out_wire}wire [3:0] ${ma_pre}${port}_context_tuser${term} + ${out_wire}wire ${ma_pre}${port}_context_tlast${term} + ${out_wire}wire ${ma_pre}${port}_context_tvalid${term} + ${in_wire}wire ${ma_pre}${port}_context_tready${term if (term == ";") or (idx < num_inputs - 1) or (num_outputs > 0) else ""} +%endfor + +%for idx, port in enumerate(config['data']['outputs']): + <% + port_tmp = config['data']['outputs'][port] + %>\ + // Payload Stream from User Logic: ${port} + ${in_wire}wire [${port_tmp['item_width'] * port_tmp['nipc'] - 1}:0] ${sl_pre}${port}_payload_tdata${term} + ${in_wire}wire [${port_tmp['nipc'] - 1}:0] ${sl_pre}${port}_payload_tkeep${term} + ${in_wire}wire ${sl_pre}${port}_payload_tlast${term} + ${in_wire}wire ${sl_pre}${port}_payload_tvalid${term} + ${out_wire}wire ${sl_pre}${port}_payload_tready${term} + // Context Stream from User Logic: ${port} + ${in_wire}wire [CHDR_W-1:0] ${sl_pre}${port}_context_tdata${term} + ${in_wire}wire [3:0] ${sl_pre}${port}_context_tuser${term} + ${in_wire}wire ${sl_pre}${port}_context_tlast${term} + ${in_wire}wire ${sl_pre}${port}_context_tvalid${term} + ${out_wire}wire ${sl_pre}${port}_context_tready${term if (term == ";") or (idx < num_outputs -1) else ""} +%endfor diff --git a/host/utils/rfnoc_blocktool/templates/modules/ctrlport_connect_template.mako b/host/utils/rfnoc_blocktool/templates/modules/ctrlport_connect_template.mako new file mode 100644 index 000000000..944f4af16 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/ctrlport_connect_template.mako @@ -0,0 +1,41 @@ + // Control Port Master + .m_ctrlport_req_wr(m_ctrlport_req_wr), + .m_ctrlport_req_rd(m_ctrlport_req_rd), + .m_ctrlport_req_addr(m_ctrlport_req_addr), + .m_ctrlport_req_data(m_ctrlport_req_data), +%if config['control']['ctrlport']['byte_mode']: + .m_ctrlport_req_byte_en(m_ctrlport_req_byte_en), +%endif +%if config['control']['ctrlport']['timed']: + .m_ctrlport_req_has_time(m_ctrlport_req_has_time), + .m_ctrlport_req_time(m_ctrlport_req_time), +%endif + .m_ctrlport_resp_ack(m_ctrlport_resp_ack), +%if config['control']['ctrlport']['has_status']: + .m_ctrlport_resp_status(m_ctrlport_resp_status), +%endif + .m_ctrlport_resp_data(m_ctrlport_resp_data), +%if config['control']['interface_direction'] != "slave": + // Control Port Slave + .s_ctrlport_req_wr(s_ctrlport_req_wr), + .s_ctrlport_req_rd(s_ctrlport_req_rd), + .s_ctrlport_req_addr(s_ctrlport_req_addr), + .s_ctrlport_req_portid(s_ctrlport_req_portid), + %if config['control']['interface_direction'] == "remote_master_slave": + .s_ctrlport_req_rem_epid(s_ctrlport_req_rem_epid), + .s_ctrlport_req_rem_portid(s_ctrlport_req_rem_portid), + %endif + .s_ctrlport_req_data(s_ctrlport_req_data), + %if config['control']['ctrlport']['byte_mode']: + .s_ctrlport_req_byte_en(s_ctrlport_req_byte_en), + %endif + %if config['control']['ctrlport']['timed']: + .s_ctrlport_req_has_time(s_ctrlport_req_has_time), + .s_ctrlport_req_time(s_ctrlport_req_time), + %endif + .s_ctrlport_resp_ack(s_ctrlport_resp_ack), + %if config['control']['ctrlport']['has_status']: + .s_ctrlport_resp_status(s_ctrlport_resp_status), + %endif + .s_ctrlport_resp_data(s_ctrlport_resp_data), +%endif diff --git a/host/utils/rfnoc_blocktool/templates/modules/ctrlport_modules_template.mako b/host/utils/rfnoc_blocktool/templates/modules/ctrlport_modules_template.mako new file mode 100644 index 000000000..9aecc2b80 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/ctrlport_modules_template.mako @@ -0,0 +1,47 @@ +<%! +import math +%> + ctrlport_endpoint #( + .THIS_PORTID(THIS_PORTID), + .SYNC_CLKS(${1 if config['control']['clk_domain'] == "rfnoc_ctrl" else 0}), + .AXIS_CTRL_MST_EN(${int(config['control']['interface_direction'] != "slave")}), + .AXIS_CTRL_SLV_EN(1), + .SLAVE_FIFO_SIZE(${math.ceil(math.log2(config['control']['fifo_depth']))}) + ) ctrlport_endpoint_i ( + .rfnoc_ctrl_clk(rfnoc_ctrl_clk), + .rfnoc_ctrl_rst(rfnoc_ctrl_rst), + .ctrlport_clk(ctrlport_clk), + .ctrlport_rst(ctrlport_rst), + .s_rfnoc_ctrl_tdata(s_rfnoc_ctrl_tdata), + .s_rfnoc_ctrl_tlast(s_rfnoc_ctrl_tlast), + .s_rfnoc_ctrl_tvalid(s_rfnoc_ctrl_tvalid), + .s_rfnoc_ctrl_tready(s_rfnoc_ctrl_tready), + .m_rfnoc_ctrl_tdata(m_rfnoc_ctrl_tdata), + .m_rfnoc_ctrl_tlast(m_rfnoc_ctrl_tlast), + .m_rfnoc_ctrl_tvalid(m_rfnoc_ctrl_tvalid), + .m_rfnoc_ctrl_tready(m_rfnoc_ctrl_tready), + .m_ctrlport_req_wr(m_ctrlport_req_wr), + .m_ctrlport_req_rd(m_ctrlport_req_rd), + .m_ctrlport_req_addr(m_ctrlport_req_addr), + .m_ctrlport_req_data(m_ctrlport_req_data), + .m_ctrlport_req_byte_en(${"m_ctrlport_req_byte_en" if config['control']['ctrlport']['byte_mode'] else ""}), + .m_ctrlport_req_has_time(${"m_ctrlport_req_has_time" if config['control']['ctrlport']['timed'] else ""}), + .m_ctrlport_req_time(${"m_ctrlport_req_time" if config['control']['ctrlport']['timed'] else ""}), + .m_ctrlport_resp_ack(m_ctrlport_resp_ack), + .m_ctrlport_resp_status(${"m_ctrlport_resp_status" if config['control']['ctrlport']['has_status'] else "'h0"}), + .m_ctrlport_resp_data(m_ctrlport_resp_data), + .s_ctrlport_req_wr(${"s_ctrlport_req_wr" if config['control']['interface_direction'] != "slave" else "'h0"}), + .s_ctrlport_req_rd(${"s_ctrlport_req_rd" if config['control']['interface_direction'] != "slave" else "'h0"}), + .s_ctrlport_req_addr(${"s_ctrlport_req_addr" if config['control']['interface_direction'] != "slave" else "'h0"}), + .s_ctrlport_req_portid(${"s_ctrlport_req_portid" if config['control']['interface_direction'] != "slave" else "'h0"}), + .s_ctrlport_req_rem_epid(${"s_ctrlport_req_rem_epid" if config['control']['interface_direction'] == "remote_master_slave" else "'h0"}), + .s_ctrlport_req_rem_portid(${"s_ctrlport_req_rem_portid" if config['control']['interface_direction'] == "remote_master_slave" else "'h0"}), + .s_ctrlport_req_data(${"s_ctrlport_req_data" if config['control']['interface_direction'] != "slave" else "'h0"}), + .s_ctrlport_req_byte_en(${"s_ctrlport_req_byte_en" if config['control']['interface_direction'] != "slave" else "'h0"}), + .s_ctrlport_req_has_time(${"s_ctrlport_req_has_time" if config['control']['interface_direction'] != "slave" else "'h0"}), + .s_ctrlport_req_time(${"s_ctrlport_req_time" if config['control']['interface_direction'] != "slave" else "'h0"}), + .s_ctrlport_resp_ack(${"s_ctrlport_resp_ack" if config['control']['interface_direction'] != "slave" else ""}), + .s_ctrlport_resp_status(${"s_ctrlport_resp_status" if config['control']['interface_direction'] != "slave" else ""}), + .s_ctrlport_resp_data(${"s_ctrlport_resp_data" if config['control']['interface_direction'] != "slave" else ""}) + ); +
\ No newline at end of file diff --git a/host/utils/rfnoc_blocktool/templates/modules/ctrlport_wires_template.mako b/host/utils/rfnoc_blocktool/templates/modules/ctrlport_wires_template.mako new file mode 100644 index 000000000..6d149ae6b --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/modules/ctrlport_wires_template.mako @@ -0,0 +1,58 @@ +<%page args="mode"/>\ +\ +<% + if mode == "shell": + sl_pre = "s_" + ma_pre = "m_" + sl_wire = "input " + ma_wire = "output " + term = "," + elif mode == "block": + sl_pre = "s_" + ma_pre = "m_" + sl_wire = "" + ma_wire = "" + term = ";" +%>\ + // Control Port Master + ${ma_wire}wire ${ma_pre}ctrlport_req_wr${term} + ${ma_wire}wire ${ma_pre}ctrlport_req_rd${term} + ${ma_wire}wire [19:0] ${ma_pre}ctrlport_req_addr${term} + ${ma_wire}wire [31:0] ${ma_pre}ctrlport_req_data${term} +%if config['control']['ctrlport']['byte_mode']: + ${ma_wire}wire [3:0] ${ma_pre}ctrlport_req_byte_en${term} +%endif +%if config['control']['ctrlport']['timed']: + ${ma_wire}wire ${ma_pre}ctrlport_req_ha${sl_pre}time${term} + ${ma_wire}wire [63:0] ${ma_pre}ctrlport_req_time${term} +%endif + ${sl_wire}wire ${ma_pre}ctrlport_resp_ack${term} +%if config['control']['ctrlport']['has_status']: + ${sl_wire}wire [1:0] ${ma_pre}ctrlport_resp_status${term} +%endif + ${sl_wire}wire [31:0] ${ma_pre}ctrlport_resp_data${term} + +%if config['control']['interface_direction'] != "slave": + // Control Port Slave + ${sl_wire}wire ${sl_pre}ctrlport_req_wr${term} + ${sl_wire}wire ${sl_pre}ctrlport_req_rd${term} + ${sl_wire}wire [19:0] ${sl_pre}ctrlport_req_addr${term} + ${sl_wire}wire [9:0] ${sl_pre}ctrlport_req_portid${term} + %if config['control']['interface_direction'] == "remote_master_slave": + ${sl_wire}wire [15:0] ${sl_pre}ctrlport_req_rem_epid${term} + ${sl_wire}wire [9:0] ${sl_pre}ctrlport_req_rem_portid${term} + %endif + ${sl_wire}wire [31:0] ${sl_pre}ctrlport_req_data${term} + %if config['control']['ctrlport']['byte_mode']: + ${sl_wire}wire [3:0] ${sl_pre}ctrlport_req_byte_en${term} + %endif + %if config['control']['ctrlport']['timed']: + ${sl_wire}wire ${sl_pre}ctrlport_req_has_time${term} + ${sl_wire}wire [63:0] ${sl_pre}ctrlport_req_time${term} + %endif + ${ma_wire}wire ${sl_pre}ctrlport_resp_ack${term} + %if config['control']['ctrlport']['has_status']: + ${ma_wire}wire [1:0] ${sl_pre}ctrlport_resp_status${term} + %endif + ${ma_wire}wire [31:0] ${sl_pre}ctrlport_resp_data${term} +%endif diff --git a/host/utils/rfnoc_blocktool/templates/noc_shell_template.v.mako b/host/utils/rfnoc_blocktool/templates/noc_shell_template.v.mako new file mode 100644 index 000000000..7fb1b17d5 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/noc_shell_template.v.mako @@ -0,0 +1,147 @@ +<%! +import math +%> +// +// Copyright 2019 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: noc_shell_${config['module_name']} +// Description: +// +// Parameters: +// +// Signals: + +module noc_shell_${config['module_name']} #( + parameter CHDR_W = 64, + parameter [9:0] THIS_PORTID = 10'd0, + parameter [5:0] MTU = 0 +)( + // Framework Interface + //------------------------------------------------------------ + // RFNoC Framework Clocks and Resets +%for clock in config['clocks']: + input wire ${clock['name']}_clk, + ${"output" if clock['name'] in ["rfnoc_chdr", "rfnoc_ctrl"] else "input"} wire ${clock['name']}_rst, +% endfor + + // RFNoC Backend Interface + input wire [511:0] rfnoc_core_config, + output wire [511:0] rfnoc_core_status, + <% + num_inputs = len(config['data']['inputs']) + num_outputs = len(config['data']['outputs']) + %> + // CHDR Input Ports (from framework) + input wire [(${num_inputs}*CHDR_W)-1:0] s_rfnoc_chdr_tdata, + input wire [${num_inputs-1}:0] s_rfnoc_chdr_tlast, + input wire [${num_inputs-1}:0] s_rfnoc_chdr_tvalid, + output wire [${num_inputs-1}:0] s_rfnoc_chdr_tready, + + // CHDR Output Ports (to framework) + output wire [(${num_outputs}*CHDR_W)-1:0] m_rfnoc_chdr_tdata, + output wire [${num_outputs-1}:0] m_rfnoc_chdr_tlast, + output wire [${num_outputs-1}:0] m_rfnoc_chdr_tvalid, + input wire [${num_outputs-1}:0] m_rfnoc_chdr_tready, + // AXIS-Ctrl Input Port (from framework) + input wire [31:0] s_rfnoc_ctrl_tdata, + input wire s_rfnoc_ctrl_tlast, + input wire s_rfnoc_ctrl_tvalid, + output wire s_rfnoc_ctrl_tready, + // AXIS-Ctrl Output Port (to framework) + output wire [31:0] m_rfnoc_ctrl_tdata, + output wire m_rfnoc_ctrl_tlast, + output wire m_rfnoc_ctrl_tvalid, + input wire m_rfnoc_ctrl_tready, + + // Client Interface + //------------------------------------------------------------ + output wire ctrlport_clk, + output wire ctrlport_rst, + +%if config['control']['fpga_iface'] == "ctrlport": +<%include file="modules/ctrlport_wires_template.mako" args="mode='shell'"/> +%elif config['control']['fpga_iface'] == "axis_ctrl": +<%include file="modules/axis_ctrl_wires_template.mako" args="mode='shell'"/> +%else: +<%include file="control wires template.mako"/> +%endif + + output wire axis_data_clk, + output wire axis_data_rst, + +%if config['data']['fpga_iface'] == "axis_chdr": + <%include file="modules/axis_chdr_wires_template.mako" args="mode='shell', num_inputs=num_inputs, num_outputs=num_outputs"/> +%elif config['data']['fpga_iface'] == "axis_rawdata": + <%include file="modules/axis_raw_wires_template.mako" args="mode='shell', num_inputs=num_inputs, num_outputs=num_outputs"/> +%else: + <%include file="data wires template.mako"/> +%endif +); + + // --------------------------------------------------- + // Backend Interface + // --------------------------------------------------- + wire data_i_flush_en; + wire [31:0] data_i_flush_timeout; + wire [63:0] data_i_flush_active; + wire [63:0] data_i_flush_done; + wire data_o_flush_en; + wire [31:0] data_o_flush_timeout; + wire [63:0] data_o_flush_active; + wire [63:0] data_o_flush_done; + + + backend_iface #( + .NOC_ID(32'h${format(config['noc_id'], "08X")}), + .NUM_DATA_I(${num_inputs}), + .NUM_DATA_O(${num_outputs}), + .CTRL_FIFOSIZE(${math.ceil(math.log2(config['control']['fifo_depth']))}), + .MTU(MTU) + ) backend_iface_i ( + .rfnoc_chdr_clk(rfnoc_chdr_clk), + .rfnoc_chdr_rst(rfnoc_chdr_rst), + .rfnoc_ctrl_clk(rfnoc_ctrl_clk), + .rfnoc_ctrl_rst(rfnoc_ctrl_rst), + .rfnoc_core_config(rfnoc_core_config), + .rfnoc_core_status(rfnoc_core_status), + .data_i_flush_en(data_i_flush_en), + .data_i_flush_timeout(data_i_flush_timeout), + .data_i_flush_active(data_i_flush_active), + .data_i_flush_done(data_i_flush_done), + .data_o_flush_en(data_o_flush_en), + .data_o_flush_timeout(data_o_flush_timeout), + .data_o_flush_active(data_o_flush_active), + .data_o_flush_done(data_o_flush_done) + ); + + // --------------------------------------------------- + // Control Path + // --------------------------------------------------- + + assign ctrlport_clk = ${config['control']['clk_domain']}_clk; + assign ctrlport_rst = ${config['control']['clk_domain']}_rst; + +%if config['control']['fpga_iface'] == "axis_ctrl": +<%include file="modules/axis_ctrl_modules_template.mako"/> +%elif config['control']['fpga_iface'] == "ctrlport": +<%include file="modules/ctrlport_modules_template.mako"/> +%else: +<%include file="control module template.mako"/> +%endif + + // --------------------------------------------------- + // Data Path + // --------------------------------------------------- + assign axis_data_clk = ${config['data']['clk_domain']}_clk; + assign axis_data_rst = ${config['data']['clk_domain']}_rst; +%if config['data']['fpga_iface'] == "axis_rawdata": +<%include file="modules/axis_raw_modules_template.mako"/> +%elif config['data']['fpga_iface'] == "axis_chdr": +<%include file="modules/axis_chdr_modules_template.mako"/> +%else: +<%include file="data module template.mako"/> +%endif + +endmodule // noc_shell_${config['module_name']} diff --git a/host/utils/rfnoc_blocktool/templates/rfnoc_block_template.v.mako b/host/utils/rfnoc_blocktool/templates/rfnoc_block_template.v.mako new file mode 100644 index 000000000..a2e03ea92 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/rfnoc_block_template.v.mako @@ -0,0 +1,151 @@ +<%! +import math +%> +// +// Copyright 2019 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_${config['module_name']} +// Description: +// +// Parameters: +// +// Signals: + +<% +num_inputs = len(config['data']['inputs']) +num_outputs = len(config['data']['outputs']) +%> + +module rfnoc_block_${config['module_name']} #( + parameter [9:0] THIS_PORTID = 10'd0, + parameter CHDR_W = 64, + parameter [5:0] MTU = ${math.ceil(math.log2(config['data']['mtu']))} +)( + // RFNoC Framework Clocks and Resets +%for clock in config['clocks']: + input wire ${clock['name']}_clk, + %if not clock['name'] in ["rfnoc_chdr", "rfnoc_ctrl"]: + input wire ${clock['name']}_rst, + %endif +%endfor + // RFNoC Backend Interface + input wire [511:0] rfnoc_core_config, + output wire [511:0] rfnoc_core_status, + // 2 CHDR Input Ports (from framework) + input wire [(CHDR_W*${num_inputs})-1:0] s_rfnoc_chdr_tdata, + input wire [1:0] s_rfnoc_chdr_tlast, + input wire [1:0] s_rfnoc_chdr_tvalid, + output wire [1:0] s_rfnoc_chdr_tready, + // 2 CHDR Output Ports (to framework) + output wire [(CHDR_W*${num_outputs})-1:0] m_rfnoc_chdr_tdata, + output wire [1:0] m_rfnoc_chdr_tlast, + output wire [1:0] m_rfnoc_chdr_tvalid, + input wire [1:0] m_rfnoc_chdr_tready, + // AXIS-Ctrl Input Port (from framework) + input wire [31:0] s_rfnoc_ctrl_tdata, + input wire s_rfnoc_ctrl_tlast, + input wire s_rfnoc_ctrl_tvalid, + output wire s_rfnoc_ctrl_tready, + // AXIS-Ctrl Output Port (to framework) + output wire [31:0] m_rfnoc_ctrl_tdata, + output wire m_rfnoc_ctrl_tlast, + output wire m_rfnoc_ctrl_tvalid, + input wire m_rfnoc_ctrl_tready +); + +%for clock in config['clocks']: + %if clock['name'] in ["rfnoc_chdr", "rfnoc_ctrl"]: + wire ${clock['name']}_rst; + %endif +%endfor + + wire ctrlport_clk; + wire ctrlport_rst; + + wire axis_data_clk; + wire axis_data_rst; + +%if config['control']['fpga_iface'] == "ctrlport": +<%include file="modules/ctrlport_wires_template.mako" args="mode='block'"/> +%elif config['control']['fpga_iface'] == "axis_ctrl": +<%include file="modules/axis_ctrl_wires_template.mako" args="mode='block'"/> +%else: +<%include file="control wires template.mako"/> +%endif + +%if config['data']['fpga_iface'] == "axis_chdr": +<%include file="modules/axis_chdr_wires_template.mako" args="mode='block', num_inputs=num_inputs, num_outputs=num_outputs"/> +%elif config['data']['fpga_iface'] == "axis_rawdata": +<%include file="modules/axis_raw_wires_template.mako" args="mode='block', num_inputs=num_inputs, num_outputs=num_outputs"/> +%else: +<%include file="data wires template.mako"/> +%endif + +//NoC Shell +noc_shell_${config['module_name']} #( + .CHDR_W (CHDR_W), + .THIS_PORTID (THIS_PORTID), + .MTU (MTU) +) noc_shell ( +%for clock in config['clocks']: + .${clock['name']}_clk(${clock['name']}_clk), + .${clock['name']}_rst(${clock['name']}_rst), +%endfor + + // RFNoC Backend Interface + .rfnoc_core_config(rfnoc_core_config), + .rfnoc_core_status(rfnoc_core_status), + + // CHDR Input Ports (from framework) + .s_rfnoc_chdr_tdata(s_rfnoc_chdr_tdata), + .s_rfnoc_chdr_tlast(s_rfnoc_chdr_tlast), + .s_rfnoc_chdr_tvalid(s_rfnoc_chdr_tvalid), + .s_rfnoc_chdr_tready(s_rfnoc_chdr_tready), + + // CHDR Output Ports (to framework) + .m_rfnoc_chdr_tdata(m_rfnoc_chdr_tdata), + .m_rfnoc_chdr_tlast(m_rfnoc_chdr_tlast), + .m_rfnoc_chdr_tvalid(m_rfnoc_chdr_tvalid), + .m_rfnoc_chdr_tready(m_rfnoc_chdr_tready), + // AXIS-Ctrl Input Port (from framework) + .s_rfnoc_ctrl_tdata(s_rfnoc_ctrl_tdata), + .s_rfnoc_ctrl_tlast(s_rfnoc_ctrl_tlast), + .s_rfnoc_ctrl_tvalid(s_rfnoc_ctrl_tvalid), + .s_rfnoc_ctrl_tready(s_rfnoc_ctrl_tready), + // AXIS-Ctrl Output Port (to framework) + .m_rfnoc_ctrl_tdata(m_rfnoc_ctrl_tdata), + .m_rfnoc_ctrl_tlast(m_rfnoc_ctrl_tlast), + .m_rfnoc_ctrl_tvalid(m_rfnoc_ctrl_tvalid), + .m_rfnoc_ctrl_tready(m_rfnoc_ctrl_tready), + + // Client Interface + //------------------------------------------------------------ + .ctrlport_clk(ctrlport_clk), + .ctrlport_rst(ctrlport_rst), + +%if config['control']['fpga_iface'] == "ctrlport": +<%include file="modules/ctrlport_connect_template.mako"/>\ +%elif config['control']['fpga_iface'] == "axis_ctrl": +<%include file="modules/axis_ctrl_connect_template.mako"/>\ +%else: +<%include file="control connect template.mako"/>\ +%endif + + .axis_data_clk(axis_data_clk), + .axis_data_rst(axis_data_rst), + +%if config['data']['fpga_iface'] == "axis_chdr": +<%include file="modules/axis_chdr_connect_template.mako" args="num_inputs=num_inputs, num_outputs=num_outputs"/>\ +%elif config['data']['fpga_iface'] == "axis_rawdata": +<%include file="modules/axis_raw_connect_template.mako" args="num_inputs=num_inputs, num_outputs=num_outputs"/>\ +%else: +<%include file="data connect template.mako"/>\ +%endif +); + + +//user code goes here + +endmodule // rfnoc_block_${config['module_name']} diff --git a/host/utils/rfnoc_blocktool/templates/rfnoc_block_template_tb.sv.mako b/host/utils/rfnoc_blocktool/templates/rfnoc_block_template_tb.sv.mako new file mode 100644 index 000000000..0bf4641b0 --- /dev/null +++ b/host/utils/rfnoc_blocktool/templates/rfnoc_block_template_tb.sv.mako @@ -0,0 +1,129 @@ +// +// Copyright 2019 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_${config['module_name']}_tb +// + +`default_nettype none + + +module rfnoc_block_${config['module_name']}_tb; + + // Simulation Timing + timeunit 1ns; + timeprecision 1ps; + + import PkgTestExec::*; + import PkgChdrUtils::*; + import PkgRfnocBlockCtrlBfm::*; + import PkgRfnocItemUtils::*; + + // Parameters + localparam [9:0] THIS_PORTID = 10'h17; + localparam [15:0] THIS_EPID = 16'hDEAD; + localparam int CHDR_W = 64; + localparam int SPP = 201; + localparam int LPP = ((SPP+1)/2); + localparam int NUM_PKTS = 50; + + localparam int PORT_SRCSNK = 0; + localparam int PORT_LOOP = 1; + + //adjust clocks to testbench needs + localparam int CHDR_CLK_PER = 5; // 200 MHz +%for clock in config['clocks']: + %if clock['name'] not in ["rfnoc_chdr", "rfnoc_ctrl"]: + localparam int ${clock['name'].upper()}_CLK_PER = 5; // 200 MHz + %endif +%endfor + + // Clock and Reset Definition + bit rfnoc_chdr_clk; +%for clock in config['clocks']: + %if clock['name'] not in ["rfnoc_chdr", "rfnoc_ctrl"]: + bit ${clock['name']}_clk; + %endif +%endfor + + sim_clock_gen #(CHDR_CLK_PER) rfnoc_chdr_clk_gen (.clk(rfnoc_chdr_clk), .rst()); +%for clock in config['clocks']: + %if clock['name'] not in ["rfnoc_chdr", "rfnoc_ctrl"]: + sim_clock_gen #(${clock['name'].upper()}_CLK_PER) ${clock['name']}_clk_gen (.clk(${clock['name']}_clk), .rst()); + %endif +%endfor + + // ---------------------------------------- + // Instantiate DUT + // ---------------------------------------- + + // Connections to DUT as interfaces: + RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_chdr_clk); // Required backend iface + AxiStreamIf #(32) m_ctrl (rfnoc_chdr_clk); // Required control iface + AxiStreamIf #(32) s_ctrl (rfnoc_chdr_clk); // Required control iface + AxiStreamIf #(CHDR_W) m0_chdr (rfnoc_chdr_clk); // Optional data iface + AxiStreamIf #(CHDR_W) m1_chdr (rfnoc_chdr_clk); // Optional data iface + AxiStreamIf #(CHDR_W) s0_chdr (rfnoc_chdr_clk); // Optional data iface + AxiStreamIf #(CHDR_W) s1_chdr (rfnoc_chdr_clk); // Optional data iface + + // Bus functional model for a software block controller + RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl; + + // DUT + rfnoc_block_${config['module_name']} #( + .THIS_PORTID (THIS_PORTID), + .CHDR_W (CHDR_W), + .MTU (10) + ) dut ( + .rfnoc_chdr_clk (backend.chdr_clk), + .rfnoc_ctrl_clk (backend.ctrl_clk), +%for clock in config['clocks']: + %if clock['name'] not in ["rfnoc_chdr", "rfnoc_ctrl"]: + .${clock['name']}_clk(${clock['name']}_clk_gen.clk), + .${clock['name']}_rst(${clock['name']}_clk_gen.rst), + %endif +%endfor + .rfnoc_core_config (backend.cfg), + .rfnoc_core_status (backend.sts), + .s_rfnoc_chdr_tdata ({m1_chdr.tdata , m0_chdr.tdata }), + .s_rfnoc_chdr_tlast ({m1_chdr.tlast , m0_chdr.tlast }), + .s_rfnoc_chdr_tvalid({m1_chdr.tvalid , m0_chdr.tvalid }), + .s_rfnoc_chdr_tready({m1_chdr.tready , m0_chdr.tready }), + .m_rfnoc_chdr_tdata ({s1_chdr.tdata , s0_chdr.tdata }), + .m_rfnoc_chdr_tlast ({s1_chdr.tlast , s0_chdr.tlast }), + .m_rfnoc_chdr_tvalid({s1_chdr.tvalid, s0_chdr.tvalid}), + .m_rfnoc_chdr_tready({s1_chdr.tready, s0_chdr.tready}), + .s_rfnoc_ctrl_tdata (m_ctrl.tdata ), + .s_rfnoc_ctrl_tlast (m_ctrl.tlast ), + .s_rfnoc_ctrl_tvalid(m_ctrl.tvalid ), + .s_rfnoc_ctrl_tready(m_ctrl.tready ), + .m_rfnoc_ctrl_tdata (s_ctrl.tdata ), + .m_rfnoc_ctrl_tlast (s_ctrl.tlast ), + .m_rfnoc_ctrl_tvalid(s_ctrl.tvalid), + .m_rfnoc_ctrl_tready(s_ctrl.tready) + ); + + // ---------------------------------------- + // Test Process + // ---------------------------------------- + TestExec test; + initial begin + // Shared Variables + // ---------------------------------------- + timeout_t timeout; + ctrl_word_t rvalue; + rvalue = 0; + + // Initialize + // ---------------------------------------- + test = new("noc_block_${config['module_name']}_tb.v"); + test.start_tb(); + + // Finish Up + // ---------------------------------------- + // Display final statistics and results + test.end_tb(); + end + +endmodule |