Skip to content

Commit

Permalink
Improve bitstream handling
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigomelo9 committed Nov 25, 2024
1 parent 3666ac7 commit ef4ae95
Show file tree
Hide file tree
Showing 14 changed files with 91 additions and 12 deletions.
2 changes: 1 addition & 1 deletion pyfpga/diamond.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def _configure(self):
self.conf['tool'] = tool
self.conf['make_cmd'] = f'{executable} {tool}.tcl'
self.conf['make_ext'] = 'tcl'
self.conf['prog_bit'] = 'bit'
self.conf['prog_bit'] = ['bit']
self.conf['prog_cmd'] = f'sh {tool}-prog.sh'
self.conf['prog_ext'] = 'sh'

Expand Down
2 changes: 1 addition & 1 deletion pyfpga/ise.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def _configure(self):
self.conf['tool'] = tool
self.conf['make_cmd'] = f'xtclsh {tool}.tcl'
self.conf['make_ext'] = 'tcl'
self.conf['prog_bit'] = 'bit'
self.conf['prog_bit'] = ['bit']
self.conf['prog_cmd'] = f'impact -batch {tool}-prog.tcl'
self.conf['prog_ext'] = 'tcl'

Expand Down
2 changes: 1 addition & 1 deletion pyfpga/libero.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def _configure(self):
self.conf['tool'] = tool
self.conf['make_cmd'] = f'{tool} SCRIPT:{tool}.tcl'
self.conf['make_ext'] = 'tcl'
self.conf['prog_bit'] = 'ppd'
self.conf['prog_bit'] = ['ppd', 'stp', 'bit', 'jed']
self.conf['prog_cmd'] = f'FPExpress SCRIPT:{tool}-prog.tcl'
self.conf['prog_ext'] = 'tcl'

Expand Down
6 changes: 5 additions & 1 deletion pyfpga/openflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def _configure(self):
self.conf['tool'] = tool
self.conf['make_cmd'] = f'bash {tool}.sh'
self.conf['make_ext'] = 'sh'
self.conf['prog_bit'] = 'bit'
self.conf['prog_bit'] = ['svf', 'bit']
self.conf['prog_cmd'] = f'bash {tool}-prog.sh'
self.conf['prog_ext'] = 'sh'

Expand All @@ -29,6 +29,10 @@ def _make_custom(self):
self.data['device'] = info['device']
self.data['package'] = info['package']

def _prog_custom(self):
info = get_info(self.data.get('part', 'hx8k-ct256'))
self.data['family'] = info['family']


def get_info(part):
"""Get info about the FPGA part.
Expand Down
10 changes: 7 additions & 3 deletions pyfpga/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,14 @@ def prog(self, bitstream=None, position=1):
raise ValueError('Invalid position.')
self.logger.info('Programming')
if not bitstream:
bitstream = f'{self.data["project"]}.{self.conf["prog_bit"]}'
for ext in self.conf['prog_bit']:
candidate = Path(self.odir) / f'{self.data["project"]}.{ext}'
if candidate.exists():
bitstream = candidate.resolve()
break
else:
bitstream = Path(bitstream).resolve().as_posix()
if not os.path.exists(bitstream):
bitstream = Path(bitstream).resolve()
if not bitstream or not bitstream.exists():
raise FileNotFoundError(bitstream)
self.data['bitstream'] = bitstream
self._prog_custom()
Expand Down
2 changes: 1 addition & 1 deletion pyfpga/quartus.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def _configure(self):
self.conf['tool'] = tool
self.conf['make_cmd'] = f'quartus_sh --script {tool}.tcl'
self.conf['make_ext'] = 'tcl'
self.conf['prog_bit'] = 'sof'
self.conf['prog_bit'] = ['sof', 'pof']
self.conf['prog_cmd'] = f'bash {tool}-prog.tcl'
self.conf['prog_ext'] = 'tcl'

Expand Down
4 changes: 2 additions & 2 deletions pyfpga/templates/openflow-prog.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ set -e
DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"

{% if family == 'ecp5' %}
$DOCKER --device /dev/bus/usb hdlc/prog openocd -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf {{ project }}.svf; exit"
$DOCKER --device /dev/bus/usb hdlc/prog openocd -f /usr/share/trellis/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf {{ bitstream }}; exit"
{% else %}
$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ project }}.bit
$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ bitstream }}
{% endif %}
2 changes: 1 addition & 1 deletion pyfpga/vivado.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def _configure(self):
self.conf['tool'] = tool
self.conf['make_cmd'] = f'{command} {tool}.tcl'
self.conf['make_ext'] = 'tcl'
self.conf['prog_bit'] = 'bit'
self.conf['prog_bit'] = ['bit']
self.conf['prog_cmd'] = f'{command} {tool}-prog.tcl'
self.conf['prog_ext'] = 'tcl'

Expand Down
25 changes: 25 additions & 0 deletions tests/mocks/FPExpress
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3

#
# Copyright (C) 2024 PyFPGA Project
#
# SPDX-License-Identifier: GPL-3.0-or-later
#

import argparse
import sys


parser = argparse.ArgumentParser()

parser.add_argument('source')

args = parser.parse_args()

tool = parser.prog

if not args.source.startswith("SCRIPT:", 0):
print('ERROR:the parameter should start width "SCRIPT:"')
sys.exit(1)

print(f'INFO:the {tool.upper()} mock has been executed')
13 changes: 12 additions & 1 deletion tests/mocks/libero
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#

import argparse
import re
import subprocess
import sys

Expand All @@ -23,10 +24,12 @@ if not args.source.startswith("SCRIPT:", 0):
print('ERROR:the parameter should start width "SCRIPT:"')
sys.exit(1)

args.source = args.source.replace('SCRIPT:', '')

tcl = f'''
proc unknown args {{ }}
source {args.source.replace('SCRIPT:', '')}
source {args.source}
'''

with open(f'{tool}-mock.tcl', 'w', encoding='utf-8') as file:
Expand All @@ -39,4 +42,12 @@ subprocess.run(
universal_newlines=True
)

pattern = r'new_project\s+-name\s+(\S+)\s'
with open(args.source, 'r', encoding='utf-8') as file:
match = re.search(pattern, file.read())
if match:
project = match.group(1)
with open(f'{project}.ppd', 'w', encoding='utf-8') as file:
pass

print(f'INFO:the {tool.upper()} mock has been executed')
9 changes: 9 additions & 0 deletions tests/mocks/quartus_sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import argparse
import os
import re
import subprocess


Expand Down Expand Up @@ -41,4 +42,12 @@ subprocess.run(
universal_newlines=True
)

pattern = r'project_new\s+(\S+)\s'
with open(args.script, 'r', encoding='utf-8') as file:
match = re.search(pattern, file.read())
if match:
project = match.group(1)
with open(f'{project}.sof', 'w', encoding='utf-8') as file:
pass

print(f'INFO:the {tool.upper()} mock has been executed')
9 changes: 9 additions & 0 deletions tests/mocks/vivado
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#

import argparse
import re
import subprocess


Expand Down Expand Up @@ -70,4 +71,12 @@ subprocess.run(
universal_newlines=True
)

pattern = r'create_project\s+-force\s+(\S+)'
with open(args.source, 'r', encoding='utf-8') as file:
match = re.search(pattern, file.read())
if match:
project = match.group(1)
with open(f'{project}.bit', 'w', encoding='utf-8') as file:
pass

print(f'INFO:the {tool.upper()} mock has been executed')
9 changes: 9 additions & 0 deletions tests/mocks/xtclsh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#

import argparse
import re
import subprocess


Expand Down Expand Up @@ -34,4 +35,12 @@ subprocess.run(
universal_newlines=True
)

pattern = r'project\s+new\s+(\S+)\.xise'
with open(args.source, 'r', encoding='utf-8') as file:
match = re.search(pattern, file.read())
if match:
project = match.group(1)
with open(f'{project}.bit', 'w', encoding='utf-8') as file:
pass

print(f'INFO:the {tool.upper()} mock has been executed')
8 changes: 8 additions & 0 deletions tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def test_diamond():
generate(tool, 'PARTNAME')
base = f'results/{tool}/{tool}'
assert Path(f'{base}.tcl').exists(), 'file not found'
assert Path(f'{base}-prog.sh').exists(), 'file not found'


def test_ise():
Expand All @@ -24,6 +25,7 @@ def test_libero():
generate(tool, 'DEVICE-PACKAGE-SPEED')
base = f'results/{tool}/{tool}'
assert Path(f'{base}.tcl').exists(), 'file not found'
assert Path(f'{base}-prog.tcl').exists(), 'file not found'


def test_openflow():
Expand Down Expand Up @@ -87,6 +89,12 @@ def generate(tool, part):
prj.make()
except RuntimeError:
pass
if tool == 'libero':
open(f'results/{tool}/{tool}.ppd', 'w').close()
elif tool == 'quartus':
open(f'results/{tool}/{tool}.sof', 'w').close()
else:
open(f'results/{tool}/{tool}.bit', 'w').close()
try:
prj.prog()
except RuntimeError:
Expand Down

0 comments on commit ef4ae95

Please sign in to comment.