Files
b210-k7-fpga/top/x400/tools/parse_versions_for_dts.py
T
61782b02d7 fpga: x400: Add support for X410 motherboard FPGA
Co-authored-by: Andrew Moch <Andrew.Moch@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Michael Auchter <michael.auchter@ni.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Co-authored-by: Hector Rubio <hrubio@ni.com>


Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
2021-06-10 11:56:58 -05:00

154 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python3
#
# Copyright 2021 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
"""
This script parses versioning information from a Verilog file and generates a
devicetree include file (.dtsi) that follows the syntax that is required by MPM
for version checking.
usage: parse-versions-for-dts.py [-h] --input INPUT --output OUTPUT
--components COMPONENTS
Arguments:
-h, --help show this help message and exit
--input INPUT The input file(s) to parse. A comma separated list can
be used to specify multiple files
--output OUTPUT The output file
--components COMPONENTS
The components for which the version information is
extracted. A comma separated list can be used to
specify multiple components.
Example call:
./parse-versions-for-dts.py \
--input regmap/global_regs_regmap_utils.vh \
--output build/component_versions.dtsi \
--components fpga
Example for variable definitions in a Verilog file
(regmap/global_regs_regmap_utils.vh):
localparam FPGA_CURRENT_VERSION_MAJOR = 'h4;
localparam FPGA_CURRENT_VERSION_MINOR = 'h2;
localparam FPGA_CURRENT_VERSION_BUILD = 'h18;
localparam FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR = 'h4;
localparam FPGA_OLDEST_COMPATIBLE_VERSION_MINOR = 'h0;
localparam FPGA_OLDEST_COMPATIBLE_VERSION_BUILD = 'h0;
localparam FPGA_VERSION_LAST_MODIFIED_TIME = 'h20111013;
Example for the generated dtsi include file (build/component_versions.dtsi)
// mpm_version fpga_current_version 4.2.24
// mpm_version fpga_oldest_compatible_version 4.0.0
// mpm_version fpga_version_last_modified_time 0x20111013
"""
import argparse
import re
import sys
def parse_args():
"""Parser for the command line arguments"""
parser = argparse.ArgumentParser(description='Parse variables from Verilog files')
parser.add_argument('--input', required=True,
help='The input file(s) to parse. A comma separated ' \
'list can be used to specify multiple files')
parser.add_argument('--output', required=True, help='The output file')
parser.add_argument('--components', required=True,
help='The components for which the version information ' \
'is extracted. A comma separated list can be used ' \
'to specify multiple components.')
args = parser.parse_args()
args.input = args.input.split(',')
args.components = args.components.split(',')
return args
def parse_variables_from_verilog(filename):
"""Parses variables from a Verilog file and stores them in a dict.
The following syntax is supported:
localparam <VARIABLE> = <VALUE>;
:param str filename: input filename
"""
pattern_dec = re.compile(r'^(\d*)$')
pattern_hex = re.compile(r'^\d*\'h(\w*)$')
def _convert_verilog_datatype(str_value):
"""Converts the Verilog value string to the corresponding Python datatype
The following notations are supported:
- decimal (e.g. 1)
- hexadecimal (e.g. 'h4)
- hexadecimal with specification of the variable width (e.g. 32'h4)
:param str str_value: the string value to be converted
"""
match_dec = pattern_dec.match(str_value)
if match_dec:
return int(match_dec.group(1))
match_hex = pattern_hex.match(str_value)
if match_hex:
return int(match_hex.group(1), 16)
return '?'
with open(filename) as f:
lines = f.read().splitlines()
pattern = re.compile(r'\s*localparam (\S*)\s*=\s*(\S*);')
variables = {}
for line in lines:
match = pattern.match(line)
if match:
key = match.group(1)
value = _convert_verilog_datatype(match.group(2))
variables[key] = value
return variables
def map_variables(variables, component):
"""map the variables as they shall appear in the generated dtsi file
:param dict variables: the variables that were parsed from the Verilog file(s)
:param str component: the name of the component
"""
COMPONENT = component.upper()
mapped_vars = {
'{}_current_version'.format(component): '{}.{}.{}'.format(
variables['{}_CURRENT_VERSION_MAJOR'.format(COMPONENT)],
variables['{}_CURRENT_VERSION_MINOR'.format(COMPONENT)],
variables['{}_CURRENT_VERSION_BUILD'.format(COMPONENT)]
),
'{}_oldest_compatible_version'.format(component): '{}.{}.{}'.format(
variables['{}_CURRENT_VERSION_MAJOR'.format(COMPONENT)],
variables['{}_CURRENT_VERSION_MINOR'.format(COMPONENT)],
variables['{}_CURRENT_VERSION_BUILD'.format(COMPONENT)]
),
'{}_version_last_modified_time'.format(component): '0x{:X}'.format(
variables['{}_VERSION_LAST_MODIFIED_TIME'.format(COMPONENT)]
),
}
return mapped_vars
def generate_dtsi_file(filename, mapped_vars):
"""Generate the dtsi file
:param str filename: the output filename
:param dict mapped_vars: the variables that shall be written to the file
"""
with open(filename, 'w') as f:
for k, v in mapped_vars.items():
f.write('// mpm_version {} {}\n'.format(k, v))
def main():
""" main function """
args = parse_args()
variables = {}
mapped_vars = {}
for file in args.input:
variables.update(parse_variables_from_verilog(file))
for component in args.components:
mapped_vars.update(map_variables(variables, component))
generate_dtsi_file(args.output, mapped_vars)
return True
if __name__ == '__main__':
sys.exit(not main())