| #!/usr/bin/env python3 |
| # |
| # Remove timing information from a verilog file, which is everything between |
| # the keywords "specify" and "endspecify". |
| # |
| # Filter a verilog file to remove any backslash continuation lines, which |
| # iverilog does not parse. If targetroot is a directory, then find and |
| # process all files in the path of targetroot. If any file to be processed |
| # is unmodified (has no backslash continuation lines), then ignore it. If |
| # any file is a symbolic link and gets modified, then remove the symbolic |
| # link before overwriting with the modified file. |
| # |
| |
| import stat |
| import sys |
| import os |
| import re |
| |
| def makeuserwritable(filepath): |
| if os.path.exists(filepath): |
| st = os.stat(filepath) |
| os.chmod(filepath, st.st_mode | stat.S_IWUSR) |
| |
| def remove_specify(vfile, outfile): |
| modified = False |
| with open(vfile, 'r') as ifile: |
| vtext = ifile.read() |
| |
| if outfile == None: |
| outfile = vfile |
| |
| # Remove backslash-followed-by-newline and absorb initial whitespace. It |
| # is unclear what initial whitespace means in this context, as the use- |
| # case that has been seen seems to work under the assumption that leading |
| # whitespace is ignored up to the amount used by the last indentation. |
| |
| vlines = re.sub('\\\\\n[ \t]*', '', vtext) |
| |
| specrex = re.compile('\n[ \t]*specify[ \t\n]+') |
| endspecrex = re.compile('\n[ \t]*endspecify') |
| smatch = specrex.search(vlines) |
| while smatch: |
| specstart = smatch.start() |
| specpos = smatch.end() |
| ematch = endspecrex.search(vlines[specpos:]) |
| specend = ematch.end() |
| vtemp = vlines[0:specstart + 1] + vlines[specpos + specend + 1:] |
| vlines = vtemp |
| smatch = specrex.search(vlines) |
| |
| if vlines != vtext: |
| # File contents have been modified, so if this file was a symbolic |
| # link, then remove it. Otherwise, overwrite the file with the |
| # modified contents. |
| if outfile == vfile: |
| if os.path.islink(vfile): |
| os.unlink(vfile) |
| if os.path.exists(outfile): |
| makeuserwritable(outfile) |
| with open(outfile, 'w') as ofile: |
| ofile.write(vlines) |
| |
| elif outfile != vfile: |
| if os.path.exists(outfile): |
| makeuserwritable(outfile) |
| with open(outfile, 'w') as ofile: |
| ofile.write(vlines) |
| |
| # If called as main, run remove_specify |
| |
| if __name__ == '__main__': |
| |
| # Divide up command line into options and arguments |
| options = [] |
| arguments = [] |
| for item in sys.argv[1:]: |
| if item.find('-', 0) == 0: |
| options.append(item) |
| else: |
| arguments.append(item) |
| |
| # Need one argument: path to verilog netlist |
| # If two arguments, then 2nd argument is the output file. |
| |
| if len(arguments) == 2: |
| netlist_path = arguments[0] |
| output_path = arguments[1] |
| remove_specify(netlist_path, output_path) |
| elif len(arguments) != 1: |
| print("Usage: remove_spcify.py <file_path> [<output_path>]") |
| elif len(arguments) == 1: |
| netlist_path = arguments[0] |
| remove_specify(netlist_path, None) |
| |