Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable consistent linting and code style with pre-commit #12

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; Copyright (C) 2023 Antmicro
; SPDX-License-Identifier: Apache-2.0
[flake8]
ignore = E203, E266, E501, W503, F403, F401
max-line-length = 100
max-complexity = 27
select = B,C,E,F,W,T4,B9
exclude =
.git,
.gitignore,
.gitmodules,
.github,
.nox,
.pytest_cache,
__pycache__,
docs/source/conf.py,
venv,
count = True
show-source = True
statistics = True
8 changes: 4 additions & 4 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ jobs:
python3 -m pip install -r dev.requirements.txt
python3 -m pip install git+https://github.com/antmicro/tuttest

- name: Lint with flake8
run: flake8 fpga_topwrap --count --show-source --statistics
- name: Run lint checks
run: nox -s isort black flake8

- name: Build
run: tuttest README.md | bash -

- name: Test with pytest
run: pytest
- name: Run pytest with nox
run: nox -s tests


Examples:
Expand Down
33 changes: 33 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (C) 2023 Antmicro
# SPDX-License-Identifier: Apache-2.0
#
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks

exclude: docs/source/conf.py
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: check-added-large-files
- id: check-docstring-first
- id: check-executables-have-shebangs
- id: check-json
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
exclude: ^(.*\.j2\.yml)$
- id: end-of-file-fixer
- id: mixed-line-ending
- id: pretty-format-json
- id: requirements-txt-fixer
- id: trailing-whitespace

- repo: local
hooks:
- id: nox
name: Nox Lint (isort black flake8)
entry: nox -s isort black flake8 --
language: system
types: [python]
require_serial: true
2 changes: 2 additions & 0 deletions dev.requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
flake8
nox
pre-commit
pytest
6 changes: 0 additions & 6 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
sphinx
sphinx_tabs

https://github.com/antmicro/sphinx-immaterial/releases/download/tip/sphinx_immaterial-0.0.post1.tip-py3-none-any.whl
https://github.com/antmicro/antmicro-sphinx-utils/archive/main.zip
https://github.com/antmicro/sphinxcontrib-internal/archive/master.zip
https://github.com/return42/linuxdoc/archive/master.zip
2 changes: 1 addition & 1 deletion docs/source/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ python -m fpga_topwrap build --sources src --design project.yml --part 'xc7z020c

## Connect Topwrap to Pipeline Manager

If you want to use Pipeline Manager as a UI for creating block design, you need to:
If you want to use Pipeline Manager as a UI for creating block design, you need to:

1. Build and run Pipeline Manager server application.

Expand Down
11 changes: 6 additions & 5 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@
# Updated documentation of the configuration options is available at
# https://www.sphinx-doc.org/en/master/usage/configuration.html

from os import environ
from datetime import datetime
from os import environ

from antmicro_sphinx_utils.defaults import antmicro_html, antmicro_latex
from antmicro_sphinx_utils.defaults import extensions as default_extensions
from antmicro_sphinx_utils.defaults import (
numfig_format,
extensions as default_extensions,
myst_enable_extensions as default_myst_enable_extensions,
)
from antmicro_sphinx_utils.defaults import (
myst_fence_as_directive as default_myst_fence_as_directive,
antmicro_html,
antmicro_latex
)
from antmicro_sphinx_utils.defaults import numfig_format

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand Down
1 change: 0 additions & 1 deletion docs/source/description_files.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,3 @@ signals:
```

The name of an interface has to be unique. We also specify a prefix which will be used as a shortened identifier.

1 change: 0 additions & 1 deletion docs/source/ipwrapper.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,3 @@ It's used to standardize names of ports that belong to interfaces to ease connec

.. automethod:: __init__
```

1 change: 0 additions & 1 deletion docs/source/wrapper_port.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,3 @@ This is used in {code}`IPWrapper` class implementation and there should be no ne

.. automethod:: __init__
```

2 changes: 1 addition & 1 deletion examples/hdmi/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ ports:
HDMI_D1_P: HDMI_D1_P
HDMI_D1_N: HDMI_D1_N
HDMI_D2_P: HDMI_D2_P
HDMI_D2_N: HDMI_D2_N
HDMI_D2_N: HDMI_D2_N

interfaces:
ps7:
Expand Down
2 changes: 1 addition & 1 deletion examples/hdmi/sources/ps7.v
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ module ps7_inst (
);
wire [ 3: 0] FCLK;
wire [19: 0] IRQF2P;

assign FCLK0 = FCLK[0];
assign FCLK1 = FCLK[1];
assign IRQF2P[0] = IRQ_F2P_0;
Expand Down
2 changes: 1 addition & 1 deletion examples/pwm/ipcores/litex_pwm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ s_axi:
in:
AWADDR: [axi_awaddr, 31, 0]
AWVALID: axi_awvalid
WDATA: [axi_wdata, 31, 0]
WDATA: [axi_wdata, 31, 0]
WSTRB: [axi_wstrb, 3, 0]
WVALID: axi_wvalid
BREADY: axi_bready
Expand Down
2 changes: 1 addition & 1 deletion examples/pwm/sources/ps7.v
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ module ps7_inst (
output MAXIGP0WVALID
);
wire [ 3: 0] FCLK;

assign FCLK0 = FCLK[0];

PS7 ps7 (
Expand Down
3 changes: 1 addition & 2 deletions fpga_topwrap/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
# SPDX-License-Identifier: Apache-2.0
from .cli import main


if __name__ == '__main__':
if __name__ == "__main__":
main()
109 changes: 61 additions & 48 deletions fpga_topwrap/cli.py
Original file line number Diff line number Diff line change
@@ -1,89 +1,102 @@
# Copyright (C) 2021-2023 Antmicro
# SPDX-License-Identifier: Apache-2.0
import logging
import os

import click
import logging
from .verilog_parser import (
VerilogModuleGenerator,
ipcore_desc_from_verilog_module
)
from .vhdl_parser import VHDLModule, ipcore_desc_from_vhdl_module
from .interface_grouper import InterfaceGrouper

from .config import config
from .design import build_design_from_yaml
from .interface_grouper import InterfaceGrouper
from .kpm_topwrap_client import kpm_run_client
from .config import config

from .verilog_parser import VerilogModuleGenerator, ipcore_desc_from_verilog_module
from .vhdl_parser import VHDLModule, ipcore_desc_from_vhdl_module

click_dir = click.Path(exists=True, file_okay=False, dir_okay=True,
readable=True)
click_file = click.Path(exists=True, file_okay=True, dir_okay=False,
readable=True)
click_dir = click.Path(exists=True, file_okay=False, dir_okay=True, readable=True)
click_file = click.Path(exists=True, file_okay=True, dir_okay=False, readable=True)

main = click.Group(help="FPGA Topwrap")


@main.command("build", help="Generate top module")
@click.option('--sources', '-s', type=click_dir,
help='Specify directory to scan for additional sources')
@click.option('--design', '-d', type=click_file, required=True,
help='Specify top design file')
@click.option('--part', '-p', help='FPGA part name')
@click.option('--iface-compliance/--no-iface-compliance', default=False,
help='Force compliance checks for predefined interfaces')
@click.option(
"--sources", "-s", type=click_dir, help="Specify directory to scan for additional sources"
)
@click.option("--design", "-d", type=click_file, required=True, help="Specify top design file")
@click.option("--part", "-p", help="FPGA part name")
@click.option(
"--iface-compliance/--no-iface-compliance",
default=False,
help="Force compliance checks for predefined interfaces",
)
def build_main(sources, design, part, iface_compliance):
config.force_interface_compliance = iface_compliance

if part is None:
logging.warning("You didn't specify part number. 'None' will be used"
"and thus your implamentation may fail.")
logging.warning(
"You didn't specify part number. 'None' will be used"
"and thus your implamentation may fail."
)

build_design_from_yaml(design, sources, part)


@main.command("parse", help="Parse HDL sources to ip core yamls")
@click.option('--use-yosys', default=False, is_flag=True,
help='Use yosys\'s read_verilog_feature to parse Verilog files')
@click.option('--iface-deduce', default=False, is_flag=True,
help='Try to group port into interfaces automatically')
@click.option('--iface', '-i', multiple=True,
help='Interface name, that ports will be grouped into')
@click.option('--dest-dir', '-d', type=click_dir, default='./',
help='Destination directory for generated yamls')
@click.argument('files', type=click_file, nargs=-1)
@click.option(
"--use-yosys",
default=False,
is_flag=True,
help="Use yosys's read_verilog_feature to parse Verilog files",
)
@click.option(
"--iface-deduce",
default=False,
is_flag=True,
help="Try to group port into interfaces automatically",
)
@click.option(
"--iface", "-i", multiple=True, help="Interface name, that ports will be grouped into"
)
@click.option(
"--dest-dir",
"-d",
type=click_dir,
default="./",
help="Destination directory for generated yamls",
)
@click.argument("files", type=click_file, nargs=-1)
def parse_main(use_yosys, iface_deduce, iface, files, dest_dir):
logging.basicConfig(level=logging.INFO)
dest_dir = os.path.dirname(dest_dir)

for filename in list(filter(lambda name: os.path.splitext(name)[-1] == ".v", files)): # noqa
for filename in list(filter(lambda name: os.path.splitext(name)[-1] == ".v", files)): # noqa
modules = VerilogModuleGenerator().get_modules(filename)
iface_grouper = InterfaceGrouper(use_yosys, iface_deduce, iface)
for verilog_mod in modules:
ipcore_desc = ipcore_desc_from_verilog_module(
verilog_mod, iface_grouper)
yaml_path = os.path.join(dest_dir, f'gen_{ipcore_desc.name}.yaml')
ipcore_desc = ipcore_desc_from_verilog_module(verilog_mod, iface_grouper)
yaml_path = os.path.join(dest_dir, f"gen_{ipcore_desc.name}.yaml")
ipcore_desc.save(yaml_path)
logging.info(
f"Verilog module '{verilog_mod.get_module_name()}'"
f"saved in file '{yaml_path}'")
f"Verilog module '{verilog_mod.get_module_name()}'" f"saved in file '{yaml_path}'"
)

for filename in list(filter(lambda name: os.path.splitext(name)[-1] in [".vhd", ".vhdl"], files)): # noqa
for filename in list(
filter(lambda name: os.path.splitext(name)[-1] in [".vhd", ".vhdl"], files)
): # noqa
# TODO - handle case with multiple VHDL modules in one file
vhdl_mod = VHDLModule(filename)
iface_grouper = InterfaceGrouper(False, iface_deduce, iface)
ipcore_desc = ipcore_desc_from_vhdl_module(vhdl_mod, iface_grouper)
yaml_path = os.path.join(dest_dir, f'gen_{ipcore_desc.name}.yaml')
yaml_path = os.path.join(dest_dir, f"gen_{ipcore_desc.name}.yaml")
ipcore_desc.save(yaml_path)
logging.info(
f"VHDL Module '{vhdl_mod.get_module_name()}'"
f"saved in file '{yaml_path}'")
logging.info(f"VHDL Module '{vhdl_mod.get_module_name()}'" f"saved in file '{yaml_path}'")


@main.command("kpm_client", help="Run a client app, that connects to"
"a running KPM server")
@click.option('--host', '-h', default='127.0.0.1',
help='KPM server address - "127.0.0.1" is default')
@click.option('--port', '-p', default=9000,
help='KPM server listening port - 9000 is default')
@main.command("kpm_client", help="Run a client app, that connects to" "a running KPM server")
@click.option(
"--host", "-h", default="127.0.0.1", help='KPM server address - "127.0.0.1" is default'
)
@click.option("--port", "-p", default=9000, help="KPM server listening port - 9000 is default")
@click.argument("yamlfiles", type=click_file, nargs=-1)
def kpm_client_main(host, port, yamlfiles):
kpm_run_client(host, port, yamlfiles)
3 changes: 2 additions & 1 deletion fpga_topwrap/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@


class Config:
""" Configuration class used to store global choices
"""Configuration class used to store global choices
for behavior of Topwrap.
"""

def __init__(self, force_interface_compliance=False):
self.force_interface_compliance = force_interface_compliance

Expand Down
30 changes: 14 additions & 16 deletions fpga_topwrap/design.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright (C) 2021-2023 Antmicro
# SPDX-License-Identifier: Apache-2.0
from yaml import load, Loader
from yaml import Loader, load

from .ipconnect import IPConnect
from .ipwrapper import IPWrapper

Expand All @@ -23,21 +24,18 @@ def build_design(design, sources_dir=None, part=None):
ports = dict()
interfaces = dict()
external = dict()
if 'ports' in design.keys():
ports = design['ports']
if 'interfaces' in design.keys():
interfaces = design['interfaces']
if 'external' in design.keys():
external = design['external']

for name, ip in design['ips'].items():
if 'parameters' not in ip.keys():
ip['parameters'] = dict()

ip_wrapper = IPWrapper(ip['file'],
ip['module'],
name,
ip['parameters'])
if "ports" in design.keys():
ports = design["ports"]
if "interfaces" in design.keys():
interfaces = design["interfaces"]
if "external" in design.keys():
external = design["external"]

for name, ip in design["ips"].items():
if "parameters" not in ip.keys():
ip["parameters"] = dict()

ip_wrapper = IPWrapper(ip["file"], ip["module"], name, ip["parameters"])

ipc.add_ip(ip_wrapper)

Expand Down
Loading