Skip to content

openflow: add configure.py #7

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ jobs:
pylint -s n openflow
git diff --check --cached
- name: Test
run: pytest test
run: |
pytest test
make -C examples/configure
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#!/usr/bin/make

check:
pycodestyle openflow
pylint -s n openflow
pycodestyle openflow examples
pylint -s n openflow examples
git diff --check --cached
pytest test
make -C examples/configure

clean:
py3clean .
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,33 @@ Currently, it is based on `GHDL`, `Yosys`, `ghdl-yosys-plugin`, `nextpnr`,

> **NOTE:** it started as part of [PyFPGA](https://github.com/PyFPGA/pyfpga)
> and will be used to solves the `openflow` **tool**.

## Installation

Openflow requires Python `>=3.6`. For now, it's only available as a git repository
hosted on GitHub. It can be installed with pip:

```
pip install 'git+https://github.com/PyFPGA/pyfpga#egg=pyfpga'
```

> On GNU/Linux, installing pip packages on the system requires `sudo`.
> Alternatively, use `--local` for installing PyFPGA in your HOME.

You can get a copy of the repository either through git clone or downloading a
tarball/zipfile:

```
git clone https://github.com/PyFPGA/openflow.git
cd openflow
```

Then, use pip from the root of the repo:

```
pip install -e .
```

> With `-e` (`--editable`) your application is installed into site-packages via
> a kind of symlink. That allows pulling changes through git or changing the
> branch, without the need to reinstall the package.
8 changes: 8 additions & 0 deletions examples/configure/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
EXAMPLES=$(wildcard *.py)

.PHONY: $(EXAMPLES)

all: $(EXAMPLES)

$(EXAMPLES):
python3 $@
8 changes: 8 additions & 0 deletions examples/configure/defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Example about default values."""

from openflow.configure import ConfigureTools

cfg = ConfigureTools()

for tool in cfg.get_tools():
print(cfg.get_command(tool))
8 changes: 8 additions & 0 deletions examples/configure/file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Example about to specify a file."""

from openflow.configure import ConfigureTools

cfg = ConfigureTools('file.yml')

for tool in cfg.get_tools():
print(cfg.get_command(tool))
15 changes: 15 additions & 0 deletions examples/configure/file.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
engine:
name: example
volumes:
- "path1:path2"
- "path3:path4"
work: .
options: global-option
tools:
example1:
name: alt-example1
container: hdlc/example1
example2:
name: alt-example2
container: hdlc/example2
options: local-option
36 changes: 36 additions & 0 deletions examples/configure/methods.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Example about to use the different methods."""

from openflow.configure import ConfigureTools

cfg = ConfigureTools()

print('* Defaults for GHDL:')
print(cfg.get_command('ghdl'))

print('* Setting a different engine:')
cfg.set_engine('podman')
print(cfg.get_command('ghdl'))

print('* Setting different volumes:')
cfg.set_volumes(['v1:v1', 'v2:v2'])
print(cfg.get_command('ghdl'))

print('* Setting a different work:')
cfg.set_work('/tmp')
print(cfg.get_command('ghdl'))

print('* Setting a global options:')
cfg.set_global_options('--global option')
print(cfg.get_command('ghdl'))

print('* Setting a new container:')
cfg.set_container('ghdl', 'alt-ghdl-container')
print(cfg.get_command('ghdl'))

print('* Setting a new tool name:')
cfg.set_name('ghdl', 'alt-ghdl-name')
print(cfg.get_command('ghdl'))

print('* Setting a local options:')
cfg.set_local_options('ghdl', '--local option')
print(cfg.get_command('ghdl'))
1 change: 1 addition & 0 deletions openflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
__version__ = '0.1.0'

from openflow.openflow import Openflow
from openflow.configure import ConfigureTools
105 changes: 105 additions & 0 deletions openflow/configure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#
# Copyright (C) 2020-2021 Rodrigo A. Melo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

"""openflow.configure

A Class to configure the OCI engine, the containers and the name of the
underlying FOSS tools.
"""


import os
from yaml import safe_load, dump


class ConfigureTools:
"""Configure Tools."""

def __init__(self, filename='.openflow.yml'):
"""Class constructor."""
userfile = os.getenv('OPENFLOW_FILE')
homefile = os.path.join(os.path.expanduser('~'), filename)
projfile = os.path.join(os.path.dirname(__file__), 'configure.yml')
if userfile is not None and os.path.exists(userfile):
filepath = userfile
elif os.path.exists(filename):
filepath = filename
elif os.path.exists(homefile):
filepath = homefile
else:
filepath = projfile
self.configs = {}
with open(filepath, 'r') as file:
self.configs = safe_load(file)

def get_command(self, tool):
"""Get the command-line needed to run a tool."""
engine = self.configs['engine']['name']
name = self.configs['tools'][tool]['name']
if engine is not None and os.getenv('OPENFLOW_OFF') is None:
oci = [
engine,
'run --rm',
'-v ' + (' -v ').join(self.configs['engine']['volumes']),
'-w ' + self.configs['engine']['work'],
self.configs['engine'].get('options', None),
self.configs['tools'][tool].get('options', None),
self.configs['tools'][tool]['container'],
name
]
return ' '.join(list(filter(None, oci)))
return name

def get_tools(self):
"""Returns the list of configured tools."""
return sorted(list(self.configs['tools'].keys()))

def dump(self):
"""Dumps the configuration in YAML format (debug purpouses)."""
return dump(self.configs)

def set_engine(self, engine):
"""Set the OCI engine."""
self.configs['engine']['name'] = engine

def unset_engine(self):
"""Unset the OCI engine. """
self.configs['engine']['name'] = None

def set_volumes(self, volumes):
"""Set the volumes of the OCI engine."""
self.configs['engine']['volumes'] = volumes

def set_work(self, work):
"""Set the working directory inside the container."""
self.configs['engine']['work'] = work

def set_global_options(self, options):
"""Set options shared by all the containers."""
self.configs['engine']['options'] = options

def set_container(self, tool, container):
"""Set the container of the specified tool."""
self.configs['tools'][tool]['container'] = container

def set_name(self, tool, name):
"""Set the name of the specified tool."""
self.configs['tools'][tool]['name'] = name

def set_local_options(self, tool, options):
"""Set options for a particular container."""
self.configs['tools'][tool]['options'] = options
35 changes: 35 additions & 0 deletions openflow/configure.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
engine:
name: docker
volumes:
- "$HOME:$HOME"
work: $PWD
tools:
ecppack:
name: ecppack
container: hdlc/prjtrellis
ghdl:
name: ghdl
container: hdlc/ghdl:yosys
icepack:
name: icepack
container: hdlc/icestorm
iceprog:
name: iceprog
container: hdlc/icestorm
icetime:
name: icetime
container: hdlc/icestorm
nextpnr-ecp5:
name: nextpnr-ecp5
container: hdlc/nextpnr:ecp5
nextpnr-ice40:
name: nextpnr-ice40
container: hdlc/nextpnr:ice40
openocd:
name: openocd
container: hdlc/prog
options: "--device /dev/bus/usb"
yosys:
name: yosys
container: hdlc/ghdl:yosys
options: "--device /dev/bus/usb"
62 changes: 62 additions & 0 deletions openflow/helpers/configure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
#
# Copyright (C) 2021 Rodrigo A. Melo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

"""
A CLI to get the full OCI command for the specified tool.
"""

import argparse

from openflow import __version__ as version
from openflow.configure import ConfigureTools


def main():
"""Solves the main functionality of this helper."""

cfg = ConfigureTools()

# Parsing the command-line.

parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)

parser.add_argument(
'-v', '--version',
action='version',
version='v{}'.format(version)
)

parser.add_argument(
'tool',
metavar='TOOL',
choices=cfg.get_tools(),
help=', '.join(cfg.get_tools())
)

args = parser.parse_args()

# Solving the functionality

print(cfg.get_command(args.tool))


if __name__ == "__main__":
main()
45 changes: 45 additions & 0 deletions openflow/openflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,51 @@ def __init__(self, name='openflow', part='hx8k-ct256'):
"""Class constructor."""
self.name = name
self.part = get_part(part)
self.set_oci()
self.set_tools()

def set_oci(self):
"""Set the OCI engine."""
self.oci = {
'engine': 'docker',
'volumes': ['$HOME:$HOME'],
'work': '$PWD',
'containers': {
'ghdl': 'hdlc/ghdl:yosys',
'yosys': 'hdlc/ghdl:yosys',
'nextpnr-ice40': 'hdlc/nextpnr:ice40',
'icetime': 'hdlc/icestorm',
'icepack': 'hdlc/icestorm',
'iceprog': 'hdlc/icestorm',
'nextpnr-ecp5': 'hdlc/nextpnr:ecp5',
'ecppack': 'hdlc/prjtrellis',
'openocd': 'hdlc/prog'
},
'tools': {
'ghdl': 'ghdl',
'yosys': 'yosys',
'nextpnr-ice40': 'nextpnr-ice40',
'icetime': 'icetime',
'icepack': 'icepack',
'iceprog': 'iceprog',
'nextpnr-ecp5': 'nextpnr-ecp5',
'ecppack': 'ecppack',
'openocd': 'openocd'
}
}

def set_tools(self):
"""Set the underlying tools."""
# Check if oci['engine'] is available
engine = self.oci['engine']
volumes = '-v ' + ('-v ').join(self.oci['volumes'])
work = '-w ' + self.oci['work']
command = '{} run --rm {} {}'.format(engine, volumes, work)
self.tools = {}
for tool in self.oci['tools']:
self.tools[tool] = '{} {} {}'.format(
command, self.oci['containers'][tool], self.oci['tools'][tool]
)

# pylint: disable=too-many-arguments
def synthesis(
Expand Down
Loading