Blame tools/extra/packager/afu_json_mgr.py

Packit 534379
#!/usr/bin/env python
Packit 534379
# Copyright(c) 2017, Intel Corporation
Packit 534379
#
Packit 534379
# Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit 534379
# modification, are permitted provided that the following conditions are met:
Packit 534379
#
Packit 534379
# * Redistributions of  source code  must retain the  above copyright notice,
Packit 534379
#  this list of conditions and the following disclaimer.
Packit 534379
# * Redistributions in binary form must reproduce the above copyright notice,
Packit 534379
#  this list of conditions and the following disclaimer in the documentation
Packit 534379
#   and/or other materials provided with the distribution.
Packit 534379
# * Neither the name  of Intel Corporation  nor the names of its contributors
Packit 534379
#   may be used to  endorse or promote  products derived  from this  software
Packit 534379
#   without specific prior written permission.
Packit 534379
#
Packit 534379
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 534379
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit 534379
# IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 534379
# ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit 534379
# LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit 534379
# CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit 534379
# SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit 534379
# INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit 534379
# CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit 534379
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit 534379
# POSSIBILITY OF SUCH DAMAGE.
Packit 534379
Packit 534379
import os
Packit 534379
import sys
Packit 534379
import argparse
Packit 534379
import re
Packit 534379
import json
Packit 534379
import zipfile
Packit 534379
import uuid
Packit 534379
from afu import AFU
Packit 534379
Packit 534379
AFU_JSON_MGR_EXEC = "afu_json_mgr"
Packit 534379
DESCRIPTION = 'Intel FPGA AFU JSON Manager'
Packit 534379
Packit 534379
USAGE = """
Packit 534379
{0}
Packit 534379
Packit 534379
{1} <cmd> [options]
Packit 534379
Packit 534379
The following values for <cmd> are currently supported:
Packit 534379
\t help - displays this message
Packit 534379
\t create-json - creates a minimal JSON file describing an AFU
Packit 534379
\t json-info - extract information from JSON file for use in C or Verilog
Packit 534379
Packit 534379
{1} <cmd> --h will give command specific help
Packit 534379
""".format(DESCRIPTION, AFU_JSON_MGR_EXEC)
Packit 534379
Packit 534379
Packit 534379
# Create an AFU JSON file, filling in a few key fields.
Packit 534379
def create_json(subargs):
Packit 534379
    # Read the template JSON file
Packit 534379
    filepath = os.path.dirname(os.path.realpath(__file__))
Packit 534379
    template_path = "schema/afu_template.json"
Packit 534379
    afu = AFU()
Packit 534379
    if (zipfile.is_zipfile(filepath)):
Packit 534379
        archive = zipfile.ZipFile(filepath, 'r')
Packit 534379
        afu.load_afu_desc_file_hdl(archive.open(template_path, "r"))
Packit 534379
    else:
Packit 534379
        afu.load_afu_desc_file_hdl(open(os.path.join(filepath,
Packit 534379
                                                     template_path), "r"))
Packit 534379
Packit 534379
    accel = afu.afu_json['afu-image']['accelerator-clusters'][0]
Packit 534379
    accel['name'] = subargs.name
Packit 534379
Packit 534379
    # Top-level interface specified?
Packit 534379
    if (subargs.top_ifc):
Packit 534379
        afu.update_afu_json(['afu-image/afu-top-interface/class:' +
Packit 534379
                             subargs.top_ifc])
Packit 534379
Packit 534379
    # Either set the specified UUID or pick one
Packit 534379
    if (subargs.uuid):
Packit 534379
        accel['accelerator-type-uuid'] = subargs.uuid
Packit 534379
    else:
Packit 534379
        accel['accelerator-type-uuid'] = str(uuid.uuid1())
Packit 534379
Packit 534379
    # The output file name is either the AFU name or a specified file path
Packit 534379
    json_path = subargs.name + '.json'
Packit 534379
    if (subargs.afu_json):
Packit 534379
        json_path = subargs.afu_json
Packit 534379
    print("Writing {0}".format(json_path))
Packit 534379
    with open(json_path, 'w') as a:
Packit 534379
        a.write(afu.dumps() + '\n')
Packit 534379
Packit 534379
Packit 534379
def emit_header_comment(f, src):
Packit 534379
    f.write('''//
Packit 534379
// Generated by afu_json_mgr from {0}
Packit 534379
//
Packit 534379
Packit 534379
'''.format(src))
Packit 534379
Packit 534379
Packit 534379
# Flatten JSON into a simple, single level dictionary to emit as header files
Packit 534379
def flatten_json(subargs):
Packit 534379
    afu = AFU(subargs.afu_json)
Packit 534379
Packit 534379
    entries = dict()
Packit 534379
Packit 534379
    emit_types = (int, bool, str, str, float)
Packit 534379
    # Don't emit some keys.  For example, user clock frequency may not be
Packit 534379
    # known at compile time, so avoid emitting potentially false information.
Packit 534379
    skip_keys = ['clock-frequency-low', 'clock-frequency-high']
Packit 534379
Packit 534379
    # Flattan all entries in afu-image that are of type emit_types
Packit 534379
    image = afu.afu_json['afu-image']
Packit 534379
    for k in sorted(image.keys()):
Packit 534379
        if (isinstance(image[k], emit_types) and k not in skip_keys):
Packit 534379
            tag = str(k).replace('-', '_')
Packit 534379
            v = image[k]
Packit 534379
            # Does it look like a number?
Packit 534379
            if (not re.match('^[0-9.]+$', str(v))):
Packit 534379
                v = '"' + str(v) + '"'
Packit 534379
            entries['afu_image_' + tag] = v
Packit 534379
Packit 534379
    # Some special names, taken from other levels
Packit 534379
    accel = image['accelerator-clusters'][0]
Packit 534379
    entries['afu_accel_name'] = '"' + accel['name'] + '"'
Packit 534379
    entries['afu_accel_uuid'] = accel['accelerator-type-uuid']
Packit 534379
    try:
Packit 534379
        # May not be present.  (Will become required eventually.)
Packit 534379
        entries['afu_top_ifc'] = '"' + \
Packit 534379
            afu.afu_json['afu-image']['afu-top-interface']['class'] + '"'
Packit 534379
    except Exception:
Packit 534379
        None
Packit 534379
Packit 534379
    return entries
Packit 534379
Packit 534379
Packit 534379
# Emit C or Verilog header files based on an AFU JSON file
Packit 534379
def json_info(entries, subargs):
Packit 534379
    afu = AFU(subargs.afu_json)
Packit 534379
Packit 534379
    # C header
Packit 534379
    if (subargs.c_hdr):
Packit 534379
        print("Writing {0}".format(subargs.c_hdr))
Packit 534379
        with open(subargs.c_hdr, 'w') as p:
Packit 534379
            emit_header_comment(p, subargs.afu_json)
Packit 534379
            p.write('#ifndef __AFU_JSON_INFO__\n')
Packit 534379
            p.write('#define __AFU_JSON_INFO__\n\n')
Packit 534379
            for k in sorted(entries.keys()):
Packit 534379
                v = entries[k]
Packit 534379
                if (k == 'afu_accel_uuid'):
Packit 534379
                    v = '"' + v.upper() + '"'
Packit 534379
                p.write('#define {0} {1}\n'.format(k.upper(), v))
Packit 534379
            p.write('\n#endif // __AFU_JSON_INFO__\n')
Packit 534379
Packit 534379
    # Verilog header
Packit 534379
    if (subargs.verilog_hdr):
Packit 534379
        print("Writing {0}".format(subargs.verilog_hdr))
Packit 534379
        with open(subargs.verilog_hdr, 'w') as p:
Packit 534379
            emit_header_comment(p, subargs.afu_json)
Packit 534379
            p.write('`ifndef __AFU_JSON_INFO__\n')
Packit 534379
            p.write('`define __AFU_JSON_INFO__\n\n')
Packit 534379
            for k in sorted(entries.keys()):
Packit 534379
                v = entries[k]
Packit 534379
                if (k == 'afu_accel_uuid'):
Packit 534379
                    v = "128'h" + entries[k].replace('-', '_')
Packit 534379
                p.write('`define {0} {1}\n'.format(k.upper(), v))
Packit 534379
            p.write('\n`endif // __AFU_JSON_INFO__\n')
Packit 534379
Packit 534379
Packit 534379
def run_afu_json_mgr():
Packit 534379
    parser = argparse.ArgumentParser(usage=USAGE, add_help=False)
Packit 534379
    parser.add_argument("cmd", nargs="?")
Packit 534379
    parser.add_argument("remain_args", nargs=argparse.REMAINDER)
Packit 534379
    args = parser.parse_args(sys.argv[1:])
Packit 534379
    cmd_description = "{0} {1}".format(AFU_JSON_MGR_EXEC, args.cmd)
Packit 534379
    subparser = argparse.ArgumentParser(description=cmd_description)
Packit 534379
    subparser._optionals.title = 'Options'
Packit 534379
Packit 534379
    if args.cmd == "help" or not args.cmd:
Packit 534379
        print(USAGE)
Packit 534379
Packit 534379
    elif args.cmd == "create-json":
Packit 534379
        subparser.usage = "\n" + cmd_description + \
Packit 534379
            " --name=<AFU_NAME> --top-ifc=<TOP_INTERFACE_CLASS>"\
Packit 534379
            " --uuid=<AFU_UUID> --afu-json=<OUTPUT_JSON>\n"
Packit 534379
        subparser.add_argument('--name', required=True,
Packit 534379
                               help='AFU name (REQUIRED)')
Packit 534379
        subparser.add_argument('--top-ifc', required=False,
Packit 534379
                               default='ccip_std_afu',
Packit 534379
                               help='Top-level interface class name. '
Packit 534379
                               'Default is ccip_std_afu.  See the output of '
Packit 534379
                               '"afu_platform_config --help" for a list of '
Packit 534379
                               'top-level interface classes.')
Packit 534379
        subparser.add_argument('--uuid', required=False,
Packit 534379
                               help='Accelerator UUID (default: chosen at '
Packit 534379
                               'random)')
Packit 534379
        subparser.add_argument('--afu-json', required=False,
Packit 534379
                               help='Output path for JSON file '
Packit 534379
                               '(default <afu_name>.json)')
Packit 534379
        subargs = subparser.parse_args(args.remain_args)
Packit 534379
        create_json(subargs)
Packit 534379
Packit 534379
    elif args.cmd == "json-info":
Packit 534379
        subparser.usage = "\n" + cmd_description + \
Packit 534379
            " --afu-json=<INPUT_JSON>"\
Packit 534379
            " --c-hdr=<OUTPUT_C_HDR_PATH>"\
Packit 534379
            " --verilog-hdr=<OUTPUT_VERILOG_HDR_PATH>\n"
Packit 534379
        subparser.add_argument('--afu-json', required=True,
Packit 534379
                               help='Input path of JSON file. ')
Packit 534379
        subparser.add_argument('--c-hdr', required=False,
Packit 534379
                               help='Path of generated C header file. ')
Packit 534379
        subparser.add_argument('--verilog-hdr', required=False,
Packit 534379
                               help='Path of generated Verilog header file. ')
Packit 534379
        subargs = subparser.parse_args(args.remain_args)
Packit 534379
        entries = flatten_json(subargs)
Packit 534379
        json_info(entries, subargs)
Packit 534379
Packit 534379
    else:
Packit 534379
        raise Exception("{0} is not a command for {1}!".format(
Packit 534379
            args.cmd, DESCRIPTION))
Packit 534379
Packit 534379
Packit 534379
def main():
Packit 534379
    try:
Packit 534379
        sys.exit(run_afu_json_mgr())
Packit 534379
    except Exception as e:
Packit 534379
        print("ERROR: {0}".format(e.__str__()))
Packit 534379
        sys.exit(1)
Packit 534379
Packit 534379
Packit 534379
if __name__ == '__main__':
Packit 534379
    main()