Skip to content

Commit 3dd16e7

Browse files
authored
Merge pull request #2 from PyFPGA/reorganize
Reorganize
2 parents 6e9c76f + e0e4a4e commit 3dd16e7

File tree

16 files changed

+262
-347
lines changed

16 files changed

+262
-347
lines changed

hdltools/apps/genstub.py

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,11 @@
66

77
"""This script generates a stub for the specified module."""
88

9-
import argparse
10-
import logging
11-
import sys
9+
from hdltools.cli_parser import cli_parser
10+
from hdltools.hdl_controller import HDLController
1211

13-
from hdltools.mod_parse import ModParse
14-
from hdltools.gen_file import GenFile
1512

16-
17-
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
18-
19-
parser = argparse.ArgumentParser()
20-
parser.add_argument('--top')
21-
parser.add_argument('--suffix', default='_stub')
22-
parser.add_argument('--output')
23-
parser.add_argument('file')
24-
args = parser.parse_args()
25-
26-
modules = ModParse(args.file)
27-
names = modules.get_names()
28-
29-
if not len(names) or (args.top and args.top not in names):
30-
logging.error('module not found')
31-
sys.exit(1)
32-
33-
if not args.top:
34-
args.top = names[0]
35-
36-
module = modules.get_module(args.top)
37-
module['name'] = args.top
38-
module['suffix'] = args.suffix
39-
40-
top = GenFile()
41-
top.render('stub', module)
42-
43-
if not args.output:
44-
print(top)
45-
else:
46-
top.write(args.output)
13+
args = cli_parser('stub')
14+
ctrl = HDLController('stub')
15+
ctrl.generate(args.file, args.top, args.suffix)
16+
ctrl.write(args.output)

hdltools/apps/genwrap.py

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,11 @@
66

77
"""This script generates a wrapper for the specified module."""
88

9-
import argparse
10-
import logging
11-
import sys
9+
from hdltools.cli_parser import cli_parser
10+
from hdltools.hdl_controller import HDLController
1211

13-
from hdltools.mod_parse import ModParse
14-
from hdltools.gen_file import GenFile
1512

16-
17-
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
18-
19-
parser = argparse.ArgumentParser()
20-
parser.add_argument('--top')
21-
parser.add_argument('--suffix', default='_wrap')
22-
parser.add_argument('--output')
23-
parser.add_argument('file')
24-
args = parser.parse_args()
25-
26-
modules = ModParse(args.file)
27-
names = modules.get_names()
28-
29-
if not len(names) or (args.top and args.top not in names):
30-
logging.error('module not found')
31-
sys.exit(1)
32-
33-
if not args.top:
34-
args.top = names[0]
35-
36-
module = modules.get_module(args.top)
37-
module['name'] = args.top
38-
module['suffix'] = args.suffix
39-
40-
top = GenFile()
41-
top.render('wrap', module)
42-
43-
if not args.output:
44-
print(top)
45-
else:
46-
top.write(args.output)
13+
args = cli_parser('wrap')
14+
ctrl = HDLController('wrap')
15+
ctrl.generate(args.file, args.top, args.suffix)
16+
ctrl.write(args.output)

hdltools/apps/modcomp.py

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,22 @@
66

77
"""This script compares two Verilog modules."""
88

9-
import argparse
109
import difflib
11-
import json
12-
import logging
1310
import sys
1411

15-
from hdltools.mod_parse import ModParse
12+
from hdltools.cli_parser import cli_parser
13+
from hdltools.hdl_controller import HDLController
1614

1715

18-
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
16+
args = cli_parser('comp')
17+
ctrl = HDLController('comp')
18+
mod1 = ctrl.generate(args.files[0], args.top1)
19+
mod2 = ctrl.generate(args.files[1], args.top2)
1920

20-
parser = argparse.ArgumentParser()
21-
parser.add_argument('--top1')
22-
parser.add_argument('--top2')
23-
parser.add_argument('files', nargs=2)
24-
args = parser.parse_args()
25-
26-
modules = ModParse(args.files[0])
27-
module1 = modules.get_module(args.top1)
28-
if not module1:
29-
logging.error('first module not found')
30-
sys.exit(1)
31-
32-
modules = ModParse(args.files[1])
33-
module2 = modules.get_module(args.top2)
34-
if not module2:
35-
logging.error('second module not found')
36-
sys.exit(1)
37-
38-
if module1 == module2:
39-
logging.info('modules are equal')
21+
if mod1 == mod2:
22+
print('INFO: modules are equal')
4023
else:
41-
logging.error('modules have differences')
42-
text1 = json.dumps(module1, indent=2, sort_keys=True).splitlines()
43-
text2 = json.dumps(module2, indent=2, sort_keys=True).splitlines()
44-
diff = difflib.unified_diff(text1, text2, lineterm='')
45-
print("\n".join(diff))
24+
print('ERROR: modules are different\n')
25+
diff = list(difflib.ndiff(mod1.splitlines(), mod2.splitlines()))
26+
print('\n'.join(diff))
4627
sys.exit(1)

hdltools/cli_parser.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#
2+
# Copyright (C) 2025 HDLtools Project
3+
#
4+
# SPDX-License-Identifier: GPL-3.0-or-later
5+
#
6+
7+
"""This file implements the command-line parser."""
8+
9+
import argparse
10+
11+
12+
def cli_parser(app):
13+
"""Parse command-line arguments based on the selected application."""
14+
parser = argparse.ArgumentParser()
15+
if app == 'comp':
16+
parser.add_argument('--top1')
17+
parser.add_argument('--top2')
18+
parser.add_argument('files', nargs=2)
19+
else:
20+
parser.add_argument('--top')
21+
parser.add_argument('--suffix', default=f'_{app}')
22+
parser.add_argument('--output')
23+
parser.add_argument('file')
24+
return parser.parse_args()

hdltools/gen_file.py

Lines changed: 0 additions & 34 deletions
This file was deleted.

hdltools/hdl_controller.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#
2+
# Copyright (C) 2025 HDLtools Project
3+
#
4+
# SPDX-License-Identifier: GPL-3.0-or-later
5+
#
6+
7+
"""
8+
This module defines the HDLController class that orchestrates the entire flow
9+
from reading and sanitizing HDL code, parsing modules, and generating output
10+
HDL code using Jinja2 templates.
11+
"""
12+
13+
import sys
14+
15+
from hdltools.hdl_reader import HDLReader
16+
from hdltools.mod_parser import ModParser
17+
from hdltools.hdl_writer import HDLWriter
18+
19+
20+
class HDLController:
21+
"""A central controller to orchestrate the HDL processing tasks."""
22+
23+
def __init__(self, template):
24+
self.reader = HDLReader()
25+
self.parser = ModParser()
26+
self.writer = HDLWriter()
27+
self.template = template
28+
29+
def generate(self, filepath, top=None, suffix=None):
30+
"""Generates HDL code from the input file."""
31+
32+
try:
33+
self.reader.read_file(filepath)
34+
except (OSError, UnicodeDecodeError):
35+
self._error(f'file not found ({filepath})')
36+
37+
raw_code = self.reader.get_code()
38+
self.parser.set_code(raw_code)
39+
self.parser.parse()
40+
41+
modules = self.parser.get_names()
42+
if not modules:
43+
self._error('module not found')
44+
if top and top not in modules:
45+
self._error(f'top not found ({top})')
46+
if not top:
47+
top = modules[0]
48+
49+
context = self.parser.get_module(top)
50+
context['name'] = top
51+
context['suffix'] = suffix
52+
self.writer.render(self.template, context)
53+
54+
return self.writer.get_code()
55+
56+
def write(self, filepath):
57+
"""Writes the generated HDL code."""
58+
if not filepath:
59+
print(self.writer.get_code())
60+
else:
61+
self.writer.write_file(filepath)
62+
63+
@staticmethod
64+
def _error(message, ecode=1):
65+
print(f'ERROR: {message}')
66+
sys.exit(ecode)

hdltools/hdl_detect.py

Lines changed: 0 additions & 72 deletions
This file was deleted.

hdltools/hdl_reader.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#
2+
# Copyright (C) 2025 HDLtools Project
3+
#
4+
# SPDX-License-Identifier: GPL-3.0-or-later
5+
#
6+
7+
"""
8+
Reads and sanitizes the input HDL code by removing comments, extra whitespaces
9+
and newlines.
10+
"""
11+
12+
import re
13+
14+
15+
class HDLReader:
16+
"""Reads and sanitizes the input HDL code."""
17+
18+
def __init__(self, code=''):
19+
self.code = code
20+
21+
def read_file(self, path):
22+
"""Reads the HDL code from file."""
23+
with open(path, 'r', encoding='utf-8') as fobj:
24+
self.code = fobj.read()
25+
26+
def set_code(self, code):
27+
"""Directly sets the HDL code."""
28+
self.code = code
29+
30+
def is_vhdl(self):
31+
"""Return True if the code seems to be VHDL."""
32+
return 'endmodule' not in self.code.lower()
33+
34+
def get_code(self):
35+
"""Retrieves the sanitized HDL code."""
36+
if self.is_vhdl():
37+
text = re.sub(r'--[^\n]*', '', self.code)
38+
else:
39+
text = re.sub(r'//[^\n]*', '', self.code)
40+
text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL)
41+
return re.sub(r'\s+', ' ', text).strip()

0 commit comments

Comments
 (0)