Skip to content
Snippets Groups Projects
Commit 0ef292de authored by Pieter Donker's avatar Pieter Donker
Browse files

delete tools dir

parent 2e024bd1
No related branches found
No related tags found
No related merge requests found
Pipeline #51305 passed
# VHDL STYLE FIX
Style fixing done:
- Remove trailing spaces.
- Add spaces around operators.
- StandardLogic to lowercase.
- Constants to lowercase.
- Keywords to lowercase.
- Types to lowercase.
- Type Conversions to lowercase.
- Resolutions to lowercase.
- Attributes to lowercase.
- Remove space between type-function and the open bracket.
## Usage:
run fix on all vhdl files:
```
cd git/hdl
. ./init_hdl.sh
./vhdl_style_fix_all_files.py -p 4
```
## Todo:
- Align all code.
- Check if all tabs are converted to spaces.
- Remove spaces between all type of functions and the open bracked.
\ No newline at end of file
#!/usr/bin/python3
# ##########################################################################
# Copyright 2020
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ##########################################################################
# ##########################################################################
# Author: Pieter Donker
# Purpose: convert hdl code to fixed format
# Description:
# This script will handle one file.
# usage:
# vhdl_style_fix.py [filename]
#
# ##########################################################################
from os import getenv, path
import sys
from argparse import ArgumentParser, RawTextHelpFormatter
from textwrap import dedent
from yaml import load, FullLoader
def main():
with open(args.filename, 'r') as fd:
data_in = fd.read()
sdata = data_in.splitlines()
if cnf["space"]["remove-trailing"]:
func = RemoveTrailingSpaces(sdata)
sdata = func.get_data()
if cnf["space"]["add-around-operators"]:
func = AddSpacesAroundOperators(sdata)
sdata = func.get_data()
if cnf["space"]["add-around-delimiters"]:
func = AddSpacesAroundDelimiters(sdata)
sdata = func.get_data()
if cnf["case"]["standard-logic"]:
func = CaseStandardLogic(sdata)
sdata = func.get_data()
if cnf["case"]["constants"]:
func = CaseConstants(sdata)
sdata = func.get_data()
if cnf["case"]["reserved-words"]:
func = CaseReservedWords(sdata)
sdata = func.get_data()
if cnf["case"]["types"]:
func = CaseTypes(sdata)
sdata = func.get_data()
if cnf["case"]["conversions"]:
func = CaseConversions(sdata)
sdata = func.get_data()
if cnf["case"]["resolutions"]:
func = CaseResolutions(sdata)
sdata = func.get_data()
if cnf["case"]["attributes"]:
func = CaseAttributes(sdata)
sdata = func.get_data()
if cnf["space"]["remove-before-bracket"]:
func = RemoveSpaceBeforeBracket(sdata)
sdata = func.get_data()
if cnf["align"]["procedure-args"]:
func = AlignProcedureArgs(sdata)
sdata = func.get_data()
data = '\n'.join(sdata) + "\n"
if data_in != data:
if args.verbose:
print(f"fix {args.filename}")
with open(args.filename, 'w') as fd:
fd.write(data)
class BaseCheck:
def __init__(self, data):
self.splitchars = []
self.tokens = None
self.data = data
self.n_data = len(self.data)
def set_data(self, data):
self.data = data
self.n_data = len(self.data)
def get_data(self):
return self.data
def check(self):
pass
def splitline(self, line):
# remove comment
code = line.split("--")[0].strip()
words = []
word = ''
for ch in code:
if ch in self.splitchars:
if word:
words.append(word.strip())
word = ''
words.append(ch)
elif ch == '"':
word += ch
elif ch == "'":
word += ch
elif ch.isascii():
word += ch
else:
pass
if word:
words.append(word)
return words
class RemoveTrailingSpaces(BaseCheck):
def __init__(self, data):
super().__init__(data)
self.check()
def check(self):
for i in range(self.n_data):
self.data[i] = self.data[i].rstrip()
class AddSpacesAroundOperators(BaseCheck):
def __init__(self, data):
super().__init__(data)
self.tokens = Tokens(cnf["tokens"]["operators"])
self.check()
def check(self):
for i in range(self.n_data):
if self.data[i].strip().startswith('--'):
continue
code_str = []
comment_str = []
operator = ''
isoperator = False
isstring = False
iscomment = False
for j in range(len(self.data[i])):
ch = self.data[i][j]
if iscomment:
comment_str.append(ch)
continue
if ch in ['"']:
if isoperator:
code_str.append(' ')
operator = ''
isoperator = False
isstring = not isstring
if isstring:
code_str.append(ch)
continue
if ch.isspace():
operator = ''
isoperator = False
elif ch.isidentifier() or ch in [")"]:
if isoperator:
code_str.append(' ')
isoperator = False
operator = ''
elif self.tokens.is_valid(ch):
if isoperator:
operator += ch
else:
isoperator = True
try:
if code_str[-1] not in [" ", "("]:
code_str.append(' ')
except IndexError:
pass
operator += ch
elif isoperator and (ch.isnumeric() or ch == "."):
of = False
for jj in range(j-2, -1, -1):
if self.data[i][jj] in [",", "(", "=", ":"]:
isoperator = False
break
if (self.data[i][jj].isidentifier()
or self.data[i][jj].isnumeric()):
of = True
break
for jj in range(j, len(self.data[i])):
if of or not isoperator:
break
if self.data[i][jj] in [",", ")", ";"]:
isoperator = False
break
if (self.data[i][jj].isspace()
or self.data[i][jj].isidentifier()):
break
if isoperator:
code_str.append(' ')
isoperator = False
else:
operator = ''
elif ch.isascii() and ch != ';':
if isoperator:
code_str.append(' ')
isoperator = False
operator = ''
code_str.append(ch)
if operator == "--":
comment_str = code_str[-3:]
code_str = code_str[:-3]
iscomment = True
operator = ''
code_line = ''.join(code_str).rstrip()
comment_line = ''.join(comment_str).strip()
for str in [" ** ", " **", "** "]:
code_line = code_line.replace(str, "**")
self.data[i] = code_line
if comment_line:
self.data[i] += " " + comment_line
class AddSpacesAroundDelimiters(BaseCheck):
def __init__(self, data):
super().__init__(data)
self.tokens = Tokens(cnf["tokens"]["delimiters"])
self.check()
def check(self):
for i in range(self.n_data):
if self.data[i].strip().startswith('--'):
continue
new_line = []
last_word = ''
isdelimiter = False
iscomment = False
for ch in self.data[i]:
if iscomment:
new_line.append(ch)
continue
if ch.isspace():
last_word = ' '
isdelimiter = False
elif ch.isidentifier():
if isdelimiter:
new_line.append(' ')
isdelimiter = False
last_word += ch
elif self.tokens.is_valid(ch):
if isdelimiter:
last_word += ch
else:
isdelimiter = True
if last_word != ' ':
new_line.append(' ')
last_word += ch
elif ch.isascii() and ch != ';':
if isdelimiter:
new_line.append(' ')
isdelimiter = False
last_word += ch
if last_word == "--":
iscomment = True
new_line.append(ch)
self.data[i] = ''.join(new_line)
class CaseCheck(BaseCheck):
def __init__(self, data, case, splitchars, tokens):
super().__init__(data)
self.case = str.lower if case == "lower" else str.upper
self.splitchars = splitchars
self.tokens = Tokens(tokens)
def check(self):
for i in range(self.n_data):
line = self.data[i]
sline = self.splitline(line)
for word in sline:
if self.tokens.is_valid(word):
line = line.replace(word, self.case(word), 1)
self.data[i] = line
class CaseReservedWords(CaseCheck):
def __init__(self, data):
super().__init__(data,
cnf["case"]["reserved-words"]["case"],
cnf["case"]["reserved-words"]["splitchars"],
cnf["tokens"]["reserved-words"])
self.check()
class CaseTypes(CaseCheck):
def __init__(self, data):
super().__init__(data,
cnf["case"]["types"]["case"],
cnf["case"]["types"]["splitchars"],
cnf["tokens"]["types"])
self.check()
class CaseConversions(CaseCheck):
def __init__(self, data):
super().__init__(data,
cnf["case"]["conversions"]["case"],
cnf["case"]["conversions"]["splitchars"],
cnf["tokens"]["conversions"])
self.check()
class CaseResolutions(CaseCheck):
def __init__(self, data):
super().__init__(data,
cnf["case"]["resolutions"]["case"],
cnf["case"]["resolutions"]["splitchars"],
cnf["tokens"]["resolutions"])
self.check()
class CaseAttributes(CaseCheck):
def __init__(self, data):
super().__init__(data,
cnf["case"]["resolutions"]["case"],
cnf["case"]["resolutions"]["splitchars"],
cnf["tokens"]["attributes"])
self.check()
def check(self):
for i in range(self.n_data):
line = self.data[i]
sline = self.splitline(line)
for j in range(len(sline)):
word = sline[j]
if self.tokens.is_valid(word):
if sline[j-1] == "'":
line = line.replace(word, word.lower(), 1)
self.data[i] = line
class CaseConstants(CaseCheck):
def __init__(self, data):
super().__init__(data,
cnf["case"]["constants"]["case"],
cnf["case"]["constants"]["splitchars"],
cnf["tokens"]["constants"])
self.check()
class CaseStandardLogic(CaseCheck):
def __init__(self, data):
super().__init__(data,
cnf["case"]["standard-logic"]["case"],
cnf["case"]["standard-logic"]["splitchars"],
cnf["tokens"]["standard-logic"])
self.check()
class RemoveSpaceBeforeBracket(BaseCheck):
def __init__(self, data):
super().__init__(data)
self.tokens = Tokens(cnf["tokens"]["types"])
self.check()
def check(self):
for i in range(self.n_data):
for t in self.tokens.all():
self.data[i] = self.data[i].replace(f"{t} (", f"{t}(")
class AlignProcedureArgs(BaseCheck):
def __init__(self, data):
super().__init__(data)
self.check()
def check(self):
proc_span = [0, 0]
pos1 = 0
for i, _ in enumerate(self.data):
line = self.data[i]
if line.strip().startswith('procedure'):
if ":" in line:
proc_span[0] = i
pos1 = line.find('(') + 2
elif proc_span[0] > 0:
line = ' ' * pos1 + line.strip()
if proc_span[0] > 0 and (line.strip().endswith('is') or line.strip().endswith(');')):
proc_span[1] = i
self.data[i] = line
if proc_span[1] > proc_span[0]:
print(proc_span)
type_len = []
name_len = []
dir_len = []
for j in range(proc_span[0], proc_span[1]+1):
sline = self.data[j][pos1:].split()
if len(sline) >= 4:
type_len.append(len(sline[0]))
name_len.append(len(sline[1]))
dir_len.append(len(sline[3]))
else:
print(f"{j}: ERROR1: {self.data[j]} -> {sline}")
sys.stdout.flush()
type_len = max(type_len)
name_len = max(name_len)
dir_len = max(dir_len)
for j in range(proc_span[0], proc_span[1]+1):
line = self.data[j][:pos1]
sline = self.data[j][pos1:].split()
if len(sline) >= 5:
line += f"{sline[0]:{type_len}s} {sline[1]:{name_len}s} {sline[2]} {sline[3]:{dir_len}s} {' '.join(sline[4:])}"
else:
print(f"{j}: ERROR2: {self.data[j]} -> {sline}")
sys.stdout.flush()
self.data[j] = line
proc_span = [0, 0]
class Tokens:
"""
Class for tokens
"""
def __init__(self, tokens):
self._tokens = tokens
def all(self):
return self._tokens
def is_valid(self, val):
if val.lower() in self._tokens:
return True
return False
if __name__ == "__main__":
# load config file
basedir = getenv("HDL_WORK")
config_file = path.join(basedir, "tools", "vhdl_style_fix.yaml")
cnf = load(open(config_file, 'r'), Loader=FullLoader)
# Parse command line arguments
parser = ArgumentParser(
description="".join(dedent("""\
vhdl style fixer:
* vhdl_style_fix.py filename -h
\n""")),
formatter_class=RawTextHelpFormatter)
parser.add_argument('filename', type=str, help="filename to fix")
parser.add_argument('-v', '--verbose', action='store_true', help="verbose output")
args = parser.parse_args()
main()
#
# config file for vhdl_style_fix.py
#
space:
remove-trailing: True
add-around-operators: True
add-around-delimiters: False
remove-before-bracket: True
indend:
apply: False
size: 2
align:
procedure-args: False
case:
standard-logic:
convert: True
case: "lower"
splitchars: [" ", ".", ";", "(", ")", ","]
constants:
convert: True
case: "lower"
splitchars: [" ", ".", ";", "(", ")", ","]
reserved-words:
convert: True
case: "lower"
splitchars: [" ", ".", ";", "(", ")"]
types:
convert: True
case: "lower"
splitchars: [" ", ".", ";", "(", ")"]
conversions:
convert: True
case: "lower"
splitchars: [" ", ".", ";", "(", ")"]
resolutions:
convert: True
case: "lower"
splitchars: [" ", ".", ";", "(", ")"]
attributes:
convert: True
case: "lower"
splitchars: [" ", ".", ";", "(", ")", "'"]
# all tokens used
tokens:
types:
- "bit"
- "bit_vector"
- "integer"
- "natural"
- "positive"
- "boolean"
- "string"
- "character"
- "real"
- "time"
- "delay_length"
- "std_ulogic"
- "std_ulogic_vector"
- "std_logic"
- "std_logic_vector"
conversions:
- "signed"
- "unsigned"
- "to_signed"
- "to_unsigned"
- "to_integer"
- "to_uint"
- "to_sint"
- "to_ureal"
- "to_sreal"
- "to_uvec"
- "to_svec"
resolutions:
- "'u'"
- "'x'"
- "'0'"
- "'1'"
- "'z'"
- "'w'"
- "'l'"
- "'h'"
- "'-'"
constants:
- "true"
- "false"
standard-logic:
- "ieee"
- "std_logic_1164"
- "numeric_std"
- "math_real"
- "std_logic_textio"
- "resize"
operators:
- "*"
- "/"
- "+"
- "-"
- "&"
- "="
- "<"
- ">"
- ":"
delimiters:
- ":"
attributes:
- "base"
- "left"
- "right"
- "high"
- "low"
- "ascending"
- "image"
- "value"
- "pos"
- "val"
- "succ"
- "pred"
- "leftof"
- "rightof"
- "range"
- "reverse_range"
- "length"
- "ascending"
- "delayed"
- "stable"
- "quiet"
- "transaction"
- "event"
- "active"
- "last_event"
- "last_active"
- "last_value"
- "driving"
- "driving_value"
- "simple_name"
- "instance_name"
- "path_name"
reserved-words:
- "abs"
- "access"
- "after"
- "alias"
- "all"
- "and"
- "architecture"
- "array"
- "assert"
- "attribute"
- "begin"
- "block"
- "body"
- "buffer"
- "bus"
- "case"
- "component"
- "configuration"
- "constant"
- "disconnect"
- "downto"
- "else"
- "elsif"
- "end"
- "entity"
- "exit"
- "file"
- "for"
- "function"
- "generate"
- "generic"
- "group"
- "guarded"
- "if"
- "impure"
- "in"
- "inertial"
- "inout"
- "is"
- "label"
- "library"
- "linkage"
- "literal"
- "loop"
- "map"
- "mod"
- "nand"
- "new"
- "next"
- "nor"
- "not"
- "null"
- "of"
- "on"
- "open"
- "or"
- "others"
- "out"
- "package"
- "port"
- "postponed"
- "procedure"
- "process"
- "pure"
- "range"
- "record"
- "register"
- "reject"
- "rem"
- "report"
- "return"
- "rol"
- "ror"
- "select"
- "severity"
- "signal"
- "shared"
- "sla"
- "sll"
- "sra"
- "srl"
- "subtype"
- "then"
- "to"
- "transport"
- "type"
- "unaffected"
- "units"
- "until"
- "use"
- "variable"
- "wait"
- "when"
- "while"
- "with"
- "xnor"
- "xor"
\ No newline at end of file
#!/usr/bin/python3
# ##########################################################################
# Copyright 2020
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ##########################################################################
# ##########################################################################
# Author: Pieter Donker
# Purpose: run vhdl_style_fix.py on all files in the hdl dir using multiple
# workers
# Description:
# -p: number of workers to use
# -v: verbose
# usage:
# cd git/hdl/
# . ./init_hdl.sh
# vhdl_style_fix_all_files.py -p 4
#
# ##########################################################################
from os import getenv, path
from sys import exit, version_info
from time import sleep
from argparse import ArgumentParser, RawTextHelpFormatter
from textwrap import dedent
from subprocess import Popen, PIPE
from multiprocessing import Process, Queue
from queue import Empty
PYTHON_VERSION = version_info[0]
def run_cmd(cmd):
""" run_cmd()
run 'cmd' in a terminal and return response
cmd: command to execute in terminal
return: 'stdout' or 'Error, stderr' in case of a error
"""
proc = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
_stdout, _stderr = proc.communicate()
if _stderr:
stderr = _stderr.decode('utf - 8') if PYTHON_VERSION == 3 else _stderr
print(stderr)
return 'Error, {}'.format(stderr)
stdout = _stdout.decode('utf - 8') if PYTHON_VERSION == 3 else _stdout
return stdout
class Worker(Process):
""" Worker, used for file checking before giving it to vsg to fix.
generated files and files with inside message 'DO NOT EDIT' are skipped.
"""
def __init__(self, id, control, in_data, out_data, verbose=None):
Process.__init__(self)
self.id = id
self.control = control
self.in_data = in_data
self.out_data = out_data
self.verbose = False if verbose is None else verbose
self.stop = False
def is_generated(self, filename):
"""
Look if 'generated' is found in the pathname.
Return the skip message and return True if found, else False
"""
if "generated" in filename:
response = f"skip {filename}: (generated file)"
self.out_data.put(response)
return True
return False
def is_do_not_edit(self, filename):
"""
Look if 'DO NOT EDIT' is found inside the file.
Return the skip message and return True if found, else False
"""
with open(filename, 'r') as fd:
data = fd.read()
if "DO NOT EDIT" in data:
response = f"skip {filename}: (DO NOT EDIT)"
self.out_data.put(response)
return True
return False
def run_fix(self, filename):
"""
Use vhdl_style_fix.py to fix the file
"""
basedir = getenv("HDL_WORK")
fixtool = path.join(basedir, "tools", "vhdl_style_fix.py")
cmd = f"{fixtool} {filename}"
if self.verbose:
cmd += " --verbose"
response = run_cmd(cmd)
self.out_data.put(response.strip())
def run(self):
while not self.stop:
try:
if not self.control.empty():
control = self.control.get()
if control == "stop":
self.stop = True
print(f"stop worker {self.id}")
# get next vhd file to process
filename = self.in_data.get(block=False)
# look if generated is part of the full-filename, skip if found
if self.is_generated(filename):
continue
# look if inside the file is a DO NOT EDIT message, skip if found
if self.is_do_not_edit(filename):
continue
# fix the vhd file with vsg
self.run_fix(filename)
except Empty:
sleep(0.001)
def main():
basedir = getenv("HDL_WORK")
print(f"basedir = {basedir}")
# dirs in basedir to check/fix
checkdirs = ["/libraries/base/", "/libraries/dsp/", "/libraries/io/",
"/libraries/technology/", "/boards/", "/applications/"]
# info for the workers, number of workers to use is given by cmdline arg --proc
n_workers = args.proc
workers = []
worker_control = [Queue() for i in range(n_workers)]
process_queue = Queue()
response_queue = Queue()
n_files = 0
n_files_done = 0
# start the workers
for id in range(n_workers):
if args.verbose:
print(f"start vsg worker {id}")
_p = Worker(id, worker_control[id], process_queue, response_queue)
workers.append(_p)
_p.start()
# put all vhd files in the
for checkdir in checkdirs:
dirname = basedir + checkdir
if args.verbose:
print(f"dirname = {dirname}")
cmd = f'find {dirname} -name "*vhd"'
response = run_cmd(cmd)
for filename in response.splitlines():
process_queue.put(filename)
n_files += 1
if args.verbose:
print(f"put {n_files} in the worker queue")
fd = open("vhdl_fix_all_response.txt", 'w')
while True:
if response_queue.empty():
sleep(0.001)
else:
response = response_queue.get()
if response:
fd.write(response + '\n')
fd.flush()
if args.verbose:
print(response)
n_files_done += 1
if n_files == n_files_done:
if args.verbose:
print("All files processed, stop workers now")
for nr in range(n_workers):
worker_control[nr].put("stop")
sleep(0.5)
for worker in workers:
worker.terminate()
break
fd.close()
return 0
if __name__ == "__main__":
# Parse command line arguments
parser = ArgumentParser(
description="".join(dedent("""
run vhdl-style-guide on all found hdl files with settings from vsg_config.yaml:
with --proc the number of vsg workers can be selected, output from this script
is put in 'vsg_fix_all_response.txt' and send to stdout if --verbose is used.
\n""")),
formatter_class=RawTextHelpFormatter)
parser.add_argument('-p', '--proc', type=int, default=4, help="number of processes to use")
parser.add_argument('-v', '--verbose', action='store_true', help="verbose output")
args = parser.parse_args()
exit_code = main()
exit(exit_code)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment