opencos-eda 0.2.52__py3-none-any.whl → 0.2.54__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opencos/commands/__init__.py +2 -0
- opencos/commands/build.py +1 -1
- opencos/commands/deps_help.py +259 -0
- opencos/commands/export.py +1 -1
- opencos/commands/flist.py +4 -1
- opencos/commands/lec.py +1 -1
- opencos/commands/open.py +2 -0
- opencos/commands/proj.py +1 -1
- opencos/commands/shell.py +1 -1
- opencos/commands/sim.py +76 -8
- opencos/commands/synth.py +1 -1
- opencos/commands/upload.py +3 -0
- opencos/commands/waves.py +1 -0
- opencos/deps/defaults.py +1 -0
- opencos/deps/deps_file.py +30 -4
- opencos/deps/deps_processor.py +72 -2
- opencos/deps_schema.py +3 -0
- opencos/eda.py +50 -26
- opencos/eda_base.py +177 -33
- opencos/eda_config.py +1 -1
- opencos/eda_config_defaults.yml +49 -3
- opencos/eda_extract_targets.py +1 -58
- opencos/tests/helpers.py +16 -0
- opencos/tests/test_eda.py +14 -3
- opencos/tests/test_tools.py +159 -132
- opencos/tools/cocotb.py +15 -14
- opencos/tools/iverilog.py +4 -24
- opencos/tools/modelsim_ase.py +70 -57
- opencos/tools/quartus.py +680 -0
- opencos/tools/questa.py +158 -90
- opencos/tools/questa_fse.py +10 -0
- opencos/tools/riviera.py +1 -0
- opencos/tools/verilator.py +9 -15
- opencos/tools/vivado.py +30 -23
- opencos/util.py +89 -15
- opencos/utils/status_constants.py +1 -0
- opencos/utils/str_helpers.py +85 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/METADATA +1 -1
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/RECORD +44 -42
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/top_level.txt +0 -0
opencos/tools/questa.py
CHANGED
|
@@ -14,7 +14,7 @@ import shutil
|
|
|
14
14
|
|
|
15
15
|
from opencos import util
|
|
16
16
|
from opencos.eda_base import Tool
|
|
17
|
-
from opencos.commands import CommandSim
|
|
17
|
+
from opencos.commands import CommandSim, CommandFList
|
|
18
18
|
|
|
19
19
|
class ToolQuesta(Tool):
|
|
20
20
|
'''Base class for CommandSimQuesta, collects version information about qrun'''
|
|
@@ -23,6 +23,7 @@ class ToolQuesta(Tool):
|
|
|
23
23
|
_EXE = 'qrun'
|
|
24
24
|
|
|
25
25
|
starter_edition = False # Aka, modelsim_ase
|
|
26
|
+
use_vopt = shutil.which('vopt') # vopt exists in qrun/vsim framework, and we'll use it.
|
|
26
27
|
sim_exe = '' # vsim or qrun
|
|
27
28
|
sim_exe_base_path = ''
|
|
28
29
|
questa_major = None
|
|
@@ -74,126 +75,193 @@ class CommandSimQuesta(CommandSim, ToolQuesta):
|
|
|
74
75
|
CommandSim.__init__(self, config)
|
|
75
76
|
ToolQuesta.__init__(self, config=self.config)
|
|
76
77
|
# add args specific to this simulator
|
|
77
|
-
self.args
|
|
78
|
-
|
|
78
|
+
self.args.update({
|
|
79
|
+
'gui': False,
|
|
80
|
+
'tcl-file': 'sim.tcl',
|
|
81
|
+
'work-lib': 'work',
|
|
82
|
+
})
|
|
83
|
+
self.args_help.update({
|
|
84
|
+
'gui': 'Run Questa in GUI mode',
|
|
85
|
+
'tcl-file': 'name of TCL file to be created for Questa simulation',
|
|
86
|
+
'work-lib': 'Questa work library name',
|
|
87
|
+
})
|
|
88
|
+
|
|
79
89
|
self.shell_command = self.sim_exe # set by ToolQuesta.get_versions(self)
|
|
90
|
+
self.vlog_commands = []
|
|
91
|
+
self.vopt_commands = []
|
|
92
|
+
self.vsim_commands = []
|
|
80
93
|
|
|
81
94
|
def set_tool_defines(self):
|
|
82
95
|
ToolQuesta.set_tool_defines(self)
|
|
83
96
|
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
# We do not override CommandSim.do_it(), CommandSim.check_logs_for_errors(...)
|
|
98
|
+
|
|
99
|
+
def prepare_compile(self):
|
|
100
|
+
self.set_tool_defines()
|
|
101
|
+
self.vlog_commands = self.get_compile_command_lists()
|
|
102
|
+
self.vopt_commands = self.get_elaborate_command_lists()
|
|
103
|
+
self.vsim_commands = self.get_simulate_command_lists()
|
|
104
|
+
self.write_sh_scripts_to_work_dir(
|
|
105
|
+
compile_lists=self.vlog_commands,
|
|
106
|
+
elaborate_lists=self.vopt_commands,
|
|
107
|
+
simulate_lists=self.vsim_commands
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def compile(self):
|
|
111
|
+
if self.args['stop-before-compile']:
|
|
112
|
+
return
|
|
113
|
+
self.run_commands_check_logs(
|
|
114
|
+
self.vlog_commands, check_logs=True, log_filename='vlog.log'
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def elaborate(self):
|
|
118
|
+
if self.args['stop-before-compile'] or self.args['stop-after-compile']:
|
|
119
|
+
return
|
|
120
|
+
self.run_commands_check_logs(
|
|
121
|
+
self.vopt_commands, check_logs=True, log_filename='vopt.log'
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def simulate(self):
|
|
125
|
+
if self.args['stop-before-compile'] or self.args['stop-after-compile'] or \
|
|
126
|
+
self.args['stop-after-elaborate']:
|
|
127
|
+
return
|
|
128
|
+
self.run_commands_check_logs(
|
|
129
|
+
self.vsim_commands, check_logs=True, log_filename='vsim.log'
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def get_compile_command_lists(self, **kwargs) -> list:
|
|
86
133
|
self.set_tool_defines()
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
#
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
ret = []
|
|
135
|
+
|
|
136
|
+
# Create work library
|
|
137
|
+
vlib_cmd = [os.path.join(self.sim_exe_base_path, 'vlib'), self.args['work-lib']]
|
|
138
|
+
ret.append(vlib_cmd)
|
|
139
|
+
|
|
140
|
+
# Map work library
|
|
141
|
+
vmap_cmd = [os.path.join(self.sim_exe_base_path, 'vmap'), 'work', self.args['work-lib']]
|
|
142
|
+
ret.append(vmap_cmd)
|
|
143
|
+
|
|
144
|
+
# Compile files
|
|
145
|
+
if self.files_v or self.files_sv:
|
|
146
|
+
vlog_cmd = [os.path.join(self.sim_exe_base_path, 'vlog'), '-64', '-sv']
|
|
147
|
+
|
|
148
|
+
# Add include directories
|
|
149
|
+
for incdir in self.incdirs:
|
|
150
|
+
vlog_cmd += [f'+incdir+{incdir}']
|
|
151
|
+
|
|
152
|
+
# Add defines
|
|
153
|
+
for key, value in self.defines.items():
|
|
154
|
+
if value is None:
|
|
155
|
+
vlog_cmd += [f'+define+{key}']
|
|
156
|
+
else:
|
|
157
|
+
vlog_cmd += [f'+define+{key}={value}']
|
|
158
|
+
|
|
159
|
+
# Add suppression flags
|
|
160
|
+
vlog_cmd += [
|
|
161
|
+
'-svinputport=net',
|
|
162
|
+
'-suppress', 'vlog-2275',
|
|
163
|
+
'-suppress', 'vlog-2583',
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
# Add source files
|
|
167
|
+
vlog_cmd += self.files_v + self.files_sv
|
|
168
|
+
|
|
169
|
+
ret.append(vlog_cmd)
|
|
170
|
+
|
|
171
|
+
# Compile VHDL files if any
|
|
172
|
+
if self.files_vhd:
|
|
173
|
+
vcom_cmd = [os.path.join(self.sim_exe_base_path, 'vcom'), '-64']
|
|
174
|
+
vcom_cmd += self.files_vhd
|
|
175
|
+
ret.append(vcom_cmd)
|
|
176
|
+
|
|
177
|
+
return ret
|
|
178
|
+
|
|
179
|
+
def get_elaborate_command_lists(self, **kwargs) -> list:
|
|
180
|
+
if self.args['stop-after-compile']:
|
|
181
|
+
return []
|
|
182
|
+
|
|
183
|
+
vopt_cmd = [os.path.join(self.sim_exe_base_path, 'vopt'), '-64']
|
|
184
|
+
|
|
185
|
+
# Add optimization flags
|
|
186
|
+
vopt_cmd += [
|
|
133
187
|
'-suppress', 'vopt-13159',
|
|
134
|
-
# Too few port connections for 'uAW_FIFO'. Expected 10, found 8
|
|
135
188
|
'-suppress', 'vopt-2685',
|
|
136
|
-
# Missing connection for port 'almostEmpty' ... same message for inputs and outputs.
|
|
137
189
|
'-note', 'vopt-2718',
|
|
138
190
|
]
|
|
139
|
-
if self.args['gui']:
|
|
140
|
-
command_list += ['-gui=interactive', '+acc', '-i']
|
|
141
|
-
elif self.args['waves']:
|
|
142
|
-
command_list += ['+acc', '-c']
|
|
143
|
-
else:
|
|
144
|
-
command_list += ['-c']
|
|
145
191
|
|
|
146
|
-
if
|
|
147
|
-
|
|
192
|
+
if self.args['gui'] or self.args['waves']:
|
|
193
|
+
vopt_cmd += ['+acc']
|
|
148
194
|
|
|
149
|
-
#
|
|
150
|
-
|
|
151
|
-
# To get this to work, need to add this, among other items:
|
|
152
|
-
# --> command_list += '''-L xil_defaultlib -L unisims_ver -L unimacro_ver
|
|
153
|
-
# -L xpm -L secureip -L xilinx_vip'''.split(" ")
|
|
195
|
+
# Add top module and output
|
|
196
|
+
vopt_cmd += [self.args['top'], '-o', 'opt_design']
|
|
154
197
|
|
|
155
|
-
|
|
156
|
-
if self.args['stop-after-elaborate']:
|
|
157
|
-
command_list += ['-elab', 'elab.output', '-do', '"quit"' ]
|
|
198
|
+
return [vopt_cmd]
|
|
158
199
|
|
|
159
|
-
|
|
200
|
+
def get_simulate_command_lists(self, **kwargs) -> list:
|
|
201
|
+
# Create TCL file
|
|
160
202
|
tcl_name = os.path.abspath(os.path.join(self.args['work-dir'], self.args['tcl-file']))
|
|
161
|
-
|
|
203
|
+
|
|
204
|
+
if self.args['waves']:
|
|
205
|
+
util.artifacts.add_extension(
|
|
206
|
+
search_paths=self.args['work-dir'], file_extension='wlf',
|
|
207
|
+
typ='waveform', description='Questa Waveform WLF file'
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
with open(tcl_name, 'w', encoding='utf-8') as fo:
|
|
162
211
|
if self.args['waves']:
|
|
163
212
|
if self.args['waves-start']:
|
|
164
213
|
print(f"run {self.args['waves-start']} ns", file=fo)
|
|
165
214
|
print("add wave -r /*", file=fo)
|
|
166
215
|
print("run -all", file=fo)
|
|
167
|
-
if
|
|
216
|
+
if self.run_in_batch_mode():
|
|
168
217
|
print("quit", file=fo)
|
|
169
|
-
command_list += ['-do', tcl_name ]
|
|
170
218
|
|
|
171
|
-
#
|
|
172
|
-
|
|
219
|
+
# Create vsim command
|
|
220
|
+
vsim_cmd = [os.path.join(self.sim_exe_base_path, 'vsim'), '-64']
|
|
173
221
|
|
|
174
|
-
|
|
175
|
-
|
|
222
|
+
if not self.run_in_batch_mode():
|
|
223
|
+
vsim_cmd += ['-gui']
|
|
224
|
+
else:
|
|
225
|
+
vsim_cmd += ['-c']
|
|
176
226
|
|
|
177
|
-
|
|
178
|
-
|
|
227
|
+
if util.args['verbose']:
|
|
228
|
+
vsim_cmd += ['-verbose']
|
|
179
229
|
|
|
180
|
-
|
|
181
|
-
|
|
230
|
+
# Add simulation arguments
|
|
231
|
+
vsim_cmd += ['-do', tcl_name, 'opt_design']
|
|
182
232
|
|
|
183
|
-
|
|
184
|
-
pass
|
|
233
|
+
return [vsim_cmd]
|
|
185
234
|
|
|
186
|
-
def
|
|
235
|
+
def get_post_simulate_command_lists(self, **kwargs) -> list:
|
|
187
236
|
return []
|
|
188
237
|
|
|
189
|
-
def
|
|
190
|
-
|
|
238
|
+
def run_in_batch_mode(self) -> bool:
|
|
239
|
+
'''Returns bool if we should run in batch mode (-c) from command line'''
|
|
240
|
+
if self.args['test-mode']:
|
|
241
|
+
return True
|
|
242
|
+
if self.args['gui']:
|
|
243
|
+
return False
|
|
244
|
+
return True
|
|
191
245
|
|
|
192
|
-
def
|
|
193
|
-
|
|
246
|
+
def artifacts_add(self, name: str, typ: str, description: str) -> None:
|
|
247
|
+
'''Override from Command.artifacts_add for better descriptions'''
|
|
248
|
+
_, leafname = os.path.split(name)
|
|
249
|
+
if leafname == 'vsim.log':
|
|
250
|
+
description = 'Questa simulation step (3/3) log from stdout/stderr'
|
|
251
|
+
elif leafname == 'vopt.log':
|
|
252
|
+
description = 'Questa elaboration step (2/3) log from stdout/stderr'
|
|
253
|
+
elif leafname == 'vlog.log':
|
|
254
|
+
description = 'Questa compile step (1/3) log from stdout/stderr'
|
|
194
255
|
|
|
195
|
-
|
|
196
|
-
|
|
256
|
+
super().artifacts_add(name=name, typ=typ, description=description)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class CommandFListQuesta(CommandFList, ToolQuesta):
|
|
260
|
+
'''CommandFListQuesta is a command handler for: eda flist --tool=questa'''
|
|
261
|
+
|
|
262
|
+
def __init__(self, config: dict):
|
|
263
|
+
CommandFList.__init__(self, config=config)
|
|
264
|
+
ToolQuesta.__init__(self, config=self.config)
|
|
197
265
|
|
|
198
266
|
|
|
199
267
|
class CommandElabQuesta(CommandSimQuesta):
|
opencos/tools/questa_fse.py
CHANGED
|
@@ -11,6 +11,7 @@ For: Questa Intel Starter FPGA Edition-64 vsim 20XX.X Simulator
|
|
|
11
11
|
import os
|
|
12
12
|
|
|
13
13
|
from opencos.tools.modelsim_ase import CommandSimModelsimAse
|
|
14
|
+
from opencos.tools.questa import CommandFListQuesta
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class CommandSimQuestaFse(CommandSimModelsimAse):
|
|
@@ -20,6 +21,7 @@ class CommandSimQuestaFse(CommandSimModelsimAse):
|
|
|
20
21
|
'''
|
|
21
22
|
_TOOL = 'questa_fse'
|
|
22
23
|
_EXE = 'vsim'
|
|
24
|
+
use_vopt = True
|
|
23
25
|
|
|
24
26
|
def __init__(self, config: dict):
|
|
25
27
|
# this will setup with self._TOOL = modelsim_ase, which is not ideal so
|
|
@@ -57,3 +59,11 @@ class CommandElabQuestaFse(CommandSimQuestaFse):
|
|
|
57
59
|
def __init__(self, config:dict):
|
|
58
60
|
super().__init__(config)
|
|
59
61
|
self.args['stop-after-elaborate'] = True
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class CommandFListQuestaFse(CommandFListQuesta):
|
|
65
|
+
'''CommandFListQuestaFse is a command handler for: eda flist --tool=questa_fse'''
|
|
66
|
+
|
|
67
|
+
def __init__(self, config: dict):
|
|
68
|
+
CommandFListQuesta.__init__(self, config=config)
|
|
69
|
+
self._TOOL = 'questa_fse'
|
opencos/tools/riviera.py
CHANGED
opencos/tools/verilator.py
CHANGED
|
@@ -135,24 +135,18 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
135
135
|
paths = ['obj_dir', 'logs']
|
|
136
136
|
util.safe_mkdirs(base=self.args['work-dir'], new_dirs=paths)
|
|
137
137
|
|
|
138
|
-
util.write_shell_command_file(dirpath=self.args['work-dir'], filename='compile_only.sh',
|
|
139
|
-
command_lists=self.verilate_command_lists, line_breaks=True)
|
|
140
|
-
|
|
141
138
|
util.write_shell_command_file(dirpath=self.args['work-dir'], filename='lint_only.sh',
|
|
142
139
|
command_lists=self.lint_only_command_lists, line_breaks=True)
|
|
143
140
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
['./compile_only.sh'],
|
|
154
|
-
['./simulate_only.sh'],
|
|
155
|
-
])
|
|
141
|
+
sim_cmd_lists = self.verilated_exec_command_lists + \
|
|
142
|
+
(self.verilated_post_exec_coverage_command_lists
|
|
143
|
+
if self.args.get('coverage', True) else [])
|
|
144
|
+
|
|
145
|
+
self.write_sh_scripts_to_work_dir(
|
|
146
|
+
compile_lists=self.verilate_command_lists,
|
|
147
|
+
elaborate_lists=[],
|
|
148
|
+
simulate_lists=sim_cmd_lists
|
|
149
|
+
)
|
|
156
150
|
|
|
157
151
|
|
|
158
152
|
def compile(self):
|
opencos/tools/vivado.py
CHANGED
|
@@ -5,6 +5,7 @@ upload, flist, open, proj.
|
|
|
5
5
|
'''
|
|
6
6
|
|
|
7
7
|
# pylint: disable=R0801 # (setting similar, but not identical, self.defines key/value pairs)
|
|
8
|
+
# pylint: disable=too-many-lines
|
|
8
9
|
|
|
9
10
|
import os
|
|
10
11
|
import re
|
|
@@ -152,22 +153,11 @@ class CommandSimVivado(CommandSim, ToolVivado):
|
|
|
152
153
|
self.xvlog_commands = self.get_compile_command_lists()
|
|
153
154
|
self.xelab_commands = self.get_elaborate_command_lists()
|
|
154
155
|
self.xsim_commands = self.get_simulate_command_lists()
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
util.write_shell_command_file(dirpath=self.args['work-dir'], filename='simulate.sh',
|
|
161
|
-
command_lists=self.xsim_commands)
|
|
162
|
-
util.write_shell_command_file(dirpath=self.args['work-dir'], filename='all.sh',
|
|
163
|
-
command_lists = [
|
|
164
|
-
['./pre_compile_dep_shell_commands.sh'],
|
|
165
|
-
['./compile.sh'],
|
|
166
|
-
['./elaborate.sh'],
|
|
167
|
-
['./simulate.sh'],
|
|
168
|
-
])
|
|
169
|
-
|
|
170
|
-
self.write_eda_config_and_args()
|
|
156
|
+
self.write_sh_scripts_to_work_dir(
|
|
157
|
+
compile_lists=self.xvlog_commands,
|
|
158
|
+
elaborate_lists=self.xelab_commands,
|
|
159
|
+
simulate_lists=self.xsim_commands
|
|
160
|
+
)
|
|
171
161
|
|
|
172
162
|
def compile(self):
|
|
173
163
|
if self.args['stop-before-compile']:
|
|
@@ -259,7 +249,7 @@ class CommandSimVivado(CommandSim, ToolVivado):
|
|
|
259
249
|
print(f"run {self.args['waves-start']} ns", file=fo)
|
|
260
250
|
print("log_wave -recursive *", file=fo)
|
|
261
251
|
print("run -all", file=fo)
|
|
262
|
-
if not self.args['gui']:
|
|
252
|
+
if not self.args['gui'] or self.args['test-mode']:
|
|
263
253
|
print("exit", file=fo)
|
|
264
254
|
|
|
265
255
|
sv_seed = str(self.args['seed'])
|
|
@@ -280,7 +270,7 @@ class CommandSimVivado(CommandSim, ToolVivado):
|
|
|
280
270
|
if sys.platform == "win32":
|
|
281
271
|
command_list[0] += ".bat"
|
|
282
272
|
command_list += self.tool_config.get('simulate-args', 'snapshot --stats').split()
|
|
283
|
-
if self.args['gui']:
|
|
273
|
+
if self.args['gui'] and not self.args['test-mode']:
|
|
284
274
|
command_list += ['-gui']
|
|
285
275
|
command_list += [
|
|
286
276
|
'--tclbatch', tcl_name.replace('\\','\\\\'), # needed for windows paths
|
|
@@ -652,14 +642,15 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
652
642
|
self.write_eda_config_and_args()
|
|
653
643
|
|
|
654
644
|
# create FLIST
|
|
655
|
-
flist_file = os.path.join(self.args['work-dir'],'build.flist')
|
|
656
|
-
util.debug(f"CommandBuildVivado: {self.args['top
|
|
645
|
+
flist_file = os.path.abspath(os.path.join(self.args['work-dir'],'build.flist'))
|
|
646
|
+
util.debug(f"CommandBuildVivado: top={self.args['top']} target={self.target}",
|
|
647
|
+
f"design={self.args['design']}")
|
|
657
648
|
|
|
658
649
|
eda_path = eda_base.get_eda_exec('flist')
|
|
659
650
|
command_list = [
|
|
660
651
|
eda_path, 'flist',
|
|
652
|
+
'--no-default-log',
|
|
661
653
|
'--tool=' + self.args['tool'],
|
|
662
|
-
self.args['top-path'],
|
|
663
654
|
'--force',
|
|
664
655
|
'--out=' + flist_file,
|
|
665
656
|
#'--no-emit-incdir',
|
|
@@ -677,6 +668,14 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
677
668
|
'--prefix-v=' + shlex.quote("add_files -norecurse "),
|
|
678
669
|
'--prefix-vhd=' + shlex.quote("add_files -norecurse "),
|
|
679
670
|
]
|
|
671
|
+
|
|
672
|
+
# create an eda.flist_input.f that we'll pass to flist:
|
|
673
|
+
with open(os.path.join(self.args['work-dir'], 'eda.flist_input.f'),
|
|
674
|
+
'w', encoding='utf-8') as f:
|
|
675
|
+
f.write('\n'.join(self.files_v + self.files_sv + self.files_vhd + ['']))
|
|
676
|
+
|
|
677
|
+
command_list.append('--input-file=eda.flist_input.f')
|
|
678
|
+
|
|
680
679
|
for key,value in self.defines.items():
|
|
681
680
|
if value is None:
|
|
682
681
|
command_list += [ f"+define+{key}" ]
|
|
@@ -691,7 +690,10 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
691
690
|
util.write_shell_command_file(dirpath=self.args['work-dir'], filename='run_eda_flist.sh',
|
|
692
691
|
command_lists=[command_list], line_breaks=True)
|
|
693
692
|
|
|
694
|
-
self.exec(cwd, command_list, tee_fpath=command_list.tee_fpath)
|
|
693
|
+
###self.exec(cwd, command_list, tee_fpath=command_list.tee_fpath)
|
|
694
|
+
# Run this from work-dir
|
|
695
|
+
self.exec(work_dir=self.args['work-dir'], command_list=command_list,
|
|
696
|
+
tee_fpath=command_list.tee_fpath)
|
|
695
697
|
|
|
696
698
|
if self.args['job-name'] == "":
|
|
697
699
|
self.args['job-name'] = self.args['design']
|
|
@@ -701,7 +703,7 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
701
703
|
command_list = [self.vivado_exe]
|
|
702
704
|
command_list += [
|
|
703
705
|
'-mode',
|
|
704
|
-
'gui' if self.args['gui'] else 'batch',
|
|
706
|
+
'gui' if self.args['gui'] and not self.args['test-mode'] else 'batch',
|
|
705
707
|
'-log', os.path.join(self.args['work-dir'], self.args['top'] + '.build.log')
|
|
706
708
|
]
|
|
707
709
|
if not util.args['verbose']:
|
|
@@ -724,6 +726,11 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
724
726
|
util.write_shell_command_file(dirpath=self.args['work-dir'], filename='run_vivado.sh',
|
|
725
727
|
command_lists=[command_list], line_breaks=True)
|
|
726
728
|
|
|
729
|
+
if self.args['stop-before-compile']:
|
|
730
|
+
util.info(f"--stop-before-compile set: scripts in : {self.args['work-dir']}")
|
|
731
|
+
return
|
|
732
|
+
|
|
733
|
+
# Run this from current working dir (not work-dir)
|
|
727
734
|
self.exec(cwd, command_list, tee_fpath=command_list.tee_fpath)
|
|
728
735
|
util.info(f"Build done, results are in: {self.args['work-dir']}")
|
|
729
736
|
|
opencos/util.py
CHANGED
|
@@ -88,6 +88,7 @@ class ArtifactTypes(Enum):
|
|
|
88
88
|
DOTF = 4
|
|
89
89
|
TCL = 5
|
|
90
90
|
SHELL = 6
|
|
91
|
+
BITSTREAM = 7
|
|
91
92
|
|
|
92
93
|
class Artifacts:
|
|
93
94
|
'''Class to hold file artifacts, for logs generated by EDA, or other artifcats created
|
|
@@ -224,16 +225,17 @@ class UtilLogger:
|
|
|
224
225
|
# util's argparser: --no-default-log, --logfile=<name>, or --force-logfile=<name>
|
|
225
226
|
default_log_enabled = False
|
|
226
227
|
default_log_filepath = os.path.join('eda.work', 'eda.log')
|
|
228
|
+
default_log_disable_with_args = ['-h', '--help'] # common argparse help
|
|
227
229
|
enable = True
|
|
228
230
|
|
|
229
231
|
def clear(self) -> None:
|
|
230
|
-
'''Resets internals'''
|
|
232
|
+
'''Resets some internals for logging, but preserve others'''
|
|
231
233
|
self.file = None
|
|
232
234
|
self.filepath = ''
|
|
233
235
|
self.time_last = 0
|
|
234
236
|
|
|
235
237
|
def stop(self) -> None:
|
|
236
|
-
'''Closes open log, resets internals'''
|
|
238
|
+
'''Closes open log, resets some internals'''
|
|
237
239
|
if self.file:
|
|
238
240
|
self.write_timestamp(f'stop - {self.filepath}')
|
|
239
241
|
info(f"Closing logfile: {self.filepath}")
|
|
@@ -364,9 +366,28 @@ def get_argparser() -> argparse.ArgumentParser:
|
|
|
364
366
|
' using $OC_ROOT/bin'))
|
|
365
367
|
parser.add_argument('--artifacts-json', **bool_action_kwargs,
|
|
366
368
|
help='Store a work-dir/artifacts.json file of known tool output files')
|
|
369
|
+
parser.add_argument('-f', '--input-file', default=[], action='append',
|
|
370
|
+
help=(
|
|
371
|
+
'Input .f file to be expanded as eda'
|
|
372
|
+
' args/defines/incdirs/files/targets'))
|
|
367
373
|
return parser
|
|
368
374
|
|
|
369
375
|
|
|
376
|
+
def get_argparser_args_list(parser: object = None) -> list:
|
|
377
|
+
'''Returns list of all args, all items will include the -- prefix (--help, etc)'''
|
|
378
|
+
if not isinstance(parser, argparse.ArgumentParser):
|
|
379
|
+
return []
|
|
380
|
+
return list(vars(parser).get('_option_string_actions', {}).keys())
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def get_argparsers_args_list(parsers: list) -> list:
|
|
384
|
+
'''Returns list of all args from list of parsers, all items have -- prefix (--help, etc)'''
|
|
385
|
+
_args_list = []
|
|
386
|
+
for parser in parsers:
|
|
387
|
+
_args_list.extend(get_argparser_args_list(parser))
|
|
388
|
+
return list(dict.fromkeys(_args_list)) # uniqify, preserve order
|
|
389
|
+
|
|
390
|
+
|
|
370
391
|
def get_argparser_short_help(parser: object = None) -> str:
|
|
371
392
|
'''Returns short help for our ArgumentParser'''
|
|
372
393
|
if not parser:
|
|
@@ -393,28 +414,81 @@ def process_token(arg: list) -> bool:
|
|
|
393
414
|
return False
|
|
394
415
|
|
|
395
416
|
|
|
396
|
-
def
|
|
417
|
+
def read_tokens_from_dot_f(filepath: str) -> list:
|
|
418
|
+
'''Returns list of tokens from a .f file'''
|
|
419
|
+
debug(f"Opening -f / --input-file '{filepath}' for contents")
|
|
420
|
+
if not os.path.isfile(filepath):
|
|
421
|
+
error(f'-f (or --input-file): {filepath} does not exist',
|
|
422
|
+
error_code=status_constants.EDA_GENERAL_FILE_NOT_FOUND)
|
|
423
|
+
return []
|
|
424
|
+
tokens = []
|
|
425
|
+
with open(filepath, encoding='utf-8') as f:
|
|
426
|
+
for line in f:
|
|
427
|
+
tokens.extend(line.split())
|
|
428
|
+
return tokens
|
|
429
|
+
|
|
430
|
+
def process_debug_args(parsed: argparse.Namespace) -> None:
|
|
431
|
+
'''Sets global debug_level based on parsed args'''
|
|
432
|
+
global debug_level # pylint: disable=global-statement
|
|
433
|
+
|
|
434
|
+
if parsed.debug_level:
|
|
435
|
+
set_debug_level(parsed.debug_level)
|
|
436
|
+
elif parsed.debug:
|
|
437
|
+
set_debug_level(1)
|
|
438
|
+
elif parsed.debug is False:
|
|
439
|
+
# not None, explicitly set to False via --no-debug
|
|
440
|
+
debug_level = 0
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def process_tokens(tokens: list) -> (argparse.Namespace, list):
|
|
397
444
|
'''Processes tokens (unparsed args list) on util's ArgumentParser
|
|
398
445
|
|
|
399
446
|
Returns tuple of (parsed Namespace, unparsed args list)
|
|
400
447
|
'''
|
|
401
448
|
global debug_level # pylint: disable=global-statement
|
|
449
|
+
debug_level = 0
|
|
402
450
|
|
|
403
|
-
|
|
451
|
+
# Deal with --debug, --debug-level, and expand all parsed.input_file (list) tokens first,
|
|
452
|
+
# for now put dot-f file contents in front of of tokens, do this in a separate custom
|
|
453
|
+
# argparser.
|
|
454
|
+
bool_action_kwargs = get_argparse_bool_action_kwargs()
|
|
455
|
+
parser = argparse.ArgumentParser(
|
|
456
|
+
prog='opencos -f/--input-file', add_help=False, allow_abbrev=False
|
|
457
|
+
)
|
|
458
|
+
parser.add_argument('--debug', **bool_action_kwargs,
|
|
459
|
+
help='Display additional debug messaging level 1 or higher')
|
|
460
|
+
parser.add_argument('--debug-level', type=int, default=0,
|
|
461
|
+
help='Set debug level messaging (default: 0)')
|
|
462
|
+
parser.add_argument('-f', '--input-file', default=[], action='append',
|
|
463
|
+
help=(
|
|
464
|
+
'Input .f file to be expanded as eda'
|
|
465
|
+
' args/defines/incdirs/files/targets'))
|
|
404
466
|
try:
|
|
405
467
|
parsed, unparsed = parser.parse_known_args(tokens + [''])
|
|
468
|
+
tokens2 = list(filter(None, unparsed))
|
|
469
|
+
except argparse.ArgumentError:
|
|
470
|
+
error(f'util -f/--input-file, problem attempting to parse_known_args for: {tokens}')
|
|
471
|
+
|
|
472
|
+
process_debug_args(parsed=parsed)
|
|
473
|
+
debug(f'util.process_tokens: {parsed=} {unparsed=} from: {tokens}')
|
|
474
|
+
|
|
475
|
+
for filepath in parsed.input_file:
|
|
476
|
+
tokens2[0:0] = read_tokens_from_dot_f(filepath)
|
|
477
|
+
|
|
478
|
+
# Continue with all normal parsing beyond --debug and -f/--input-file,
|
|
479
|
+
# Note that we re-parse everything in case there was --debug or --debug-level in
|
|
480
|
+
# the .f file(s), or anything else that this argparser would pick up.
|
|
481
|
+
parser = get_argparser()
|
|
482
|
+
try:
|
|
483
|
+
parsed, unparsed = parser.parse_known_args(tokens2 + [''])
|
|
406
484
|
unparsed = list(filter(None, unparsed))
|
|
407
485
|
except argparse.ArgumentError:
|
|
408
|
-
error(f'problem attempting to parse_known_args for
|
|
486
|
+
error(f'util: problem attempting to parse_known_args for tokens={tokens2}')
|
|
409
487
|
|
|
410
|
-
|
|
411
|
-
set_debug_level(parsed.debug_level)
|
|
412
|
-
elif parsed.debug:
|
|
413
|
-
set_debug_level(1)
|
|
414
|
-
else:
|
|
415
|
-
debug_level = 0
|
|
488
|
+
process_debug_args(parsed=parsed)
|
|
416
489
|
|
|
417
|
-
|
|
490
|
+
if parsed.input_file:
|
|
491
|
+
warning(f'Skipping nested -f/--input-file(s) {parsed.input_file}')
|
|
418
492
|
|
|
419
493
|
# clear existing artifacts dicts (mostly for pytests repeatedly calling eda.main),
|
|
420
494
|
# set artifacts.enabled based on args['artifacts-json']
|
|
@@ -426,7 +500,7 @@ def process_tokens(tokens:list) -> (argparse.Namespace, list):
|
|
|
426
500
|
start_log(parsed.logfile, force=False)
|
|
427
501
|
elif parsed.default_log and \
|
|
428
502
|
not parsed.version and \
|
|
429
|
-
not any(x in unparsed for x in
|
|
503
|
+
not any(x in unparsed for x in global_log.default_log_disable_with_args) and \
|
|
430
504
|
(parsed.force_logfile is None and parsed.logfile is None):
|
|
431
505
|
# Use a forced logfile in the eda.work/eda.log:
|
|
432
506
|
# avoid this if someone has --help arg not yet parsed.
|
|
@@ -434,9 +508,9 @@ def process_tokens(tokens:list) -> (argparse.Namespace, list):
|
|
|
434
508
|
start_log(global_log.default_log_filepath, force=True)
|
|
435
509
|
|
|
436
510
|
parsed_as_dict = vars(parsed)
|
|
437
|
-
for key,value in parsed_as_dict.items():
|
|
511
|
+
for key, value in parsed_as_dict.items():
|
|
438
512
|
key = key.replace('_', '-')
|
|
439
|
-
if value is not None:
|
|
513
|
+
if key in args and value is not None:
|
|
440
514
|
args[key] = value # only update with non-None values to our global 'args' dict
|
|
441
515
|
|
|
442
516
|
return parsed, unparsed
|