| #!/usr/bin/env python3 | |
| ''' | |
| Concatenate Verilog source files and process include directives inside them. | |
| Usage: concatenate_v_sources.py [-h] inputfile [inputfile ...] outputfile | |
| ''' | |
| import argparse | |
| import sys | |
| import re | |
| from os import path | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument( | |
| "inputfile", | |
| nargs='+', | |
| type=argparse.FileType('r'), | |
| help="Input Verilog file" | |
| ) | |
| parser.add_argument( | |
| "outputfile", type=argparse.FileType('w'), help="Output file" | |
| ) | |
| include_re = re.compile(r'^`include *"([^"]+)"', flags=re.MULTILINE) | |
| slash_star_re = re.compile(r'\s*/\*.*\*/\s*', flags=re.DOTALL) | |
| slash_slash_re = re.compile(r'\s*//[^\n]*') | |
| v2x_re = re.compile( | |
| r'.*\(\*.*((DELAY)|(CLOCK)|(MODEL)|(SETUP)|(HOLD)|(FASM)).*\*\)\n' | |
| ) | |
| def process_includes(file, includes_list): | |
| file_name = path.realpath(file.name) | |
| if file_name in includes_list: | |
| return '' | |
| includes_list.append(file_name) | |
| code = file.read() | |
| code = slash_star_re.sub('', code) | |
| code = slash_slash_re.sub('', code) | |
| code = v2x_re.sub('', code) | |
| def process_match(match): | |
| include_path = path.join(path.dirname(file_name), match[1]) | |
| include_file = open(include_path, 'r') | |
| return process_includes(include_file, includes_list) | |
| rel_file_name = path.relpath(file_name) | |
| result = f'// {rel_file_name} {{{{{{\n' + \ | |
| include_re.sub(process_match, code) + \ | |
| f'// {rel_file_name} }}}}}}\n' | |
| return result | |
| def main(argv): | |
| args = parser.parse_args(argv[1:]) | |
| print(args) | |
| includes_list = [] | |
| print( | |
| *(process_includes(f, includes_list) for f in args.inputfile), | |
| sep='\n', | |
| end='', | |
| file=args.outputfile | |
| ) | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(main(sys.argv)) |