Skip to content

Commit ef4ae95

Browse files
committed
Improve bitstream handling
1 parent 3666ac7 commit ef4ae95

File tree

14 files changed

+91
-12
lines changed

14 files changed

+91
-12
lines changed

pyfpga/diamond.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def _configure(self):
2121
self.conf['tool'] = tool
2222
self.conf['make_cmd'] = f'{executable} {tool}.tcl'
2323
self.conf['make_ext'] = 'tcl'
24-
self.conf['prog_bit'] = 'bit'
24+
self.conf['prog_bit'] = ['bit']
2525
self.conf['prog_cmd'] = f'sh {tool}-prog.sh'
2626
self.conf['prog_ext'] = 'sh'
2727

pyfpga/ise.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def _configure(self):
2121
self.conf['tool'] = tool
2222
self.conf['make_cmd'] = f'xtclsh {tool}.tcl'
2323
self.conf['make_ext'] = 'tcl'
24-
self.conf['prog_bit'] = 'bit'
24+
self.conf['prog_bit'] = ['bit']
2525
self.conf['prog_cmd'] = f'impact -batch {tool}-prog.tcl'
2626
self.conf['prog_ext'] = 'tcl'
2727

pyfpga/libero.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def _configure(self):
2121
self.conf['tool'] = tool
2222
self.conf['make_cmd'] = f'{tool} SCRIPT:{tool}.tcl'
2323
self.conf['make_ext'] = 'tcl'
24-
self.conf['prog_bit'] = 'ppd'
24+
self.conf['prog_bit'] = ['ppd', 'stp', 'bit', 'jed']
2525
self.conf['prog_cmd'] = f'FPExpress SCRIPT:{tool}-prog.tcl'
2626
self.conf['prog_ext'] = 'tcl'
2727

pyfpga/openflow.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def _configure(self):
1919
self.conf['tool'] = tool
2020
self.conf['make_cmd'] = f'bash {tool}.sh'
2121
self.conf['make_ext'] = 'sh'
22-
self.conf['prog_bit'] = 'bit'
22+
self.conf['prog_bit'] = ['svf', 'bit']
2323
self.conf['prog_cmd'] = f'bash {tool}-prog.sh'
2424
self.conf['prog_ext'] = 'sh'
2525

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

32+
def _prog_custom(self):
33+
info = get_info(self.data.get('part', 'hx8k-ct256'))
34+
self.data['family'] = info['family']
35+
3236

3337
def get_info(part):
3438
"""Get info about the FPGA part.

pyfpga/project.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,14 @@ def prog(self, bitstream=None, position=1):
253253
raise ValueError('Invalid position.')
254254
self.logger.info('Programming')
255255
if not bitstream:
256-
bitstream = f'{self.data["project"]}.{self.conf["prog_bit"]}'
256+
for ext in self.conf['prog_bit']:
257+
candidate = Path(self.odir) / f'{self.data["project"]}.{ext}'
258+
if candidate.exists():
259+
bitstream = candidate.resolve()
260+
break
257261
else:
258-
bitstream = Path(bitstream).resolve().as_posix()
259-
if not os.path.exists(bitstream):
262+
bitstream = Path(bitstream).resolve()
263+
if not bitstream or not bitstream.exists():
260264
raise FileNotFoundError(bitstream)
261265
self.data['bitstream'] = bitstream
262266
self._prog_custom()

pyfpga/quartus.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def _configure(self):
1919
self.conf['tool'] = tool
2020
self.conf['make_cmd'] = f'quartus_sh --script {tool}.tcl'
2121
self.conf['make_ext'] = 'tcl'
22-
self.conf['prog_bit'] = 'sof'
22+
self.conf['prog_bit'] = ['sof', 'pof']
2323
self.conf['prog_cmd'] = f'bash {tool}-prog.tcl'
2424
self.conf['prog_ext'] = 'tcl'
2525

pyfpga/templates/openflow-prog.jinja

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ set -e
1111
DOCKER="docker run --user $(id -u):$(id -g) --rm -v $HOME:$HOME -w $PWD"
1212

1313
{% if family == 'ecp5' %}
14-
$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"
14+
$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"
1515
{% else %}
16-
$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ project }}.bit
16+
$DOCKER --device /dev/bus/usb hdlc/prog iceprog {{ bitstream }}
1717
{% endif %}

pyfpga/vivado.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def _configure(self):
2020
self.conf['tool'] = tool
2121
self.conf['make_cmd'] = f'{command} {tool}.tcl'
2222
self.conf['make_ext'] = 'tcl'
23-
self.conf['prog_bit'] = 'bit'
23+
self.conf['prog_bit'] = ['bit']
2424
self.conf['prog_cmd'] = f'{command} {tool}-prog.tcl'
2525
self.conf['prog_ext'] = 'tcl'
2626

tests/mocks/FPExpress

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python3
2+
3+
#
4+
# Copyright (C) 2024 PyFPGA Project
5+
#
6+
# SPDX-License-Identifier: GPL-3.0-or-later
7+
#
8+
9+
import argparse
10+
import sys
11+
12+
13+
parser = argparse.ArgumentParser()
14+
15+
parser.add_argument('source')
16+
17+
args = parser.parse_args()
18+
19+
tool = parser.prog
20+
21+
if not args.source.startswith("SCRIPT:", 0):
22+
print('ERROR:the parameter should start width "SCRIPT:"')
23+
sys.exit(1)
24+
25+
print(f'INFO:the {tool.upper()} mock has been executed')

tests/mocks/libero

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#
88

99
import argparse
10+
import re
1011
import subprocess
1112
import sys
1213

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

27+
args.source = args.source.replace('SCRIPT:', '')
28+
2629
tcl = f'''
2730
proc unknown args {{ }}
2831
29-
source {args.source.replace('SCRIPT:', '')}
32+
source {args.source}
3033
'''
3134

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

45+
pattern = r'new_project\s+-name\s+(\S+)\s'
46+
with open(args.source, 'r', encoding='utf-8') as file:
47+
match = re.search(pattern, file.read())
48+
if match:
49+
project = match.group(1)
50+
with open(f'{project}.ppd', 'w', encoding='utf-8') as file:
51+
pass
52+
4253
print(f'INFO:the {tool.upper()} mock has been executed')

tests/mocks/quartus_sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import argparse
1010
import os
11+
import re
1112
import subprocess
1213

1314

@@ -41,4 +42,12 @@ subprocess.run(
4142
universal_newlines=True
4243
)
4344

45+
pattern = r'project_new\s+(\S+)\s'
46+
with open(args.script, 'r', encoding='utf-8') as file:
47+
match = re.search(pattern, file.read())
48+
if match:
49+
project = match.group(1)
50+
with open(f'{project}.sof', 'w', encoding='utf-8') as file:
51+
pass
52+
4453
print(f'INFO:the {tool.upper()} mock has been executed')

tests/mocks/vivado

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#
88

99
import argparse
10+
import re
1011
import subprocess
1112

1213

@@ -70,4 +71,12 @@ subprocess.run(
7071
universal_newlines=True
7172
)
7273

74+
pattern = r'create_project\s+-force\s+(\S+)'
75+
with open(args.source, 'r', encoding='utf-8') as file:
76+
match = re.search(pattern, file.read())
77+
if match:
78+
project = match.group(1)
79+
with open(f'{project}.bit', 'w', encoding='utf-8') as file:
80+
pass
81+
7382
print(f'INFO:the {tool.upper()} mock has been executed')

tests/mocks/xtclsh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#
88

99
import argparse
10+
import re
1011
import subprocess
1112

1213

@@ -34,4 +35,12 @@ subprocess.run(
3435
universal_newlines=True
3536
)
3637

38+
pattern = r'project\s+new\s+(\S+)\.xise'
39+
with open(args.source, 'r', encoding='utf-8') as file:
40+
match = re.search(pattern, file.read())
41+
if match:
42+
project = match.group(1)
43+
with open(f'{project}.bit', 'w', encoding='utf-8') as file:
44+
pass
45+
3746
print(f'INFO:the {tool.upper()} mock has been executed')

tests/test_tools.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ def test_diamond():
99
generate(tool, 'PARTNAME')
1010
base = f'results/{tool}/{tool}'
1111
assert Path(f'{base}.tcl').exists(), 'file not found'
12+
assert Path(f'{base}-prog.sh').exists(), 'file not found'
1213

1314

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

2830

2931
def test_openflow():
@@ -87,6 +89,12 @@ def generate(tool, part):
8789
prj.make()
8890
except RuntimeError:
8991
pass
92+
if tool == 'libero':
93+
open(f'results/{tool}/{tool}.ppd', 'w').close()
94+
elif tool == 'quartus':
95+
open(f'results/{tool}/{tool}.sof', 'w').close()
96+
else:
97+
open(f'results/{tool}/{tool}.bit', 'w').close()
9098
try:
9199
prj.prog()
92100
except RuntimeError:

0 commit comments

Comments
 (0)