siliconcompiler 0.32.3__py3-none-any.whl → 0.33.0__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.
- siliconcompiler/__init__.py +19 -2
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc.py +2 -2
- siliconcompiler/apps/sc_install.py +3 -3
- siliconcompiler/apps/sc_issue.py +1 -1
- siliconcompiler/apps/sc_remote.py +4 -4
- siliconcompiler/apps/sc_show.py +2 -2
- siliconcompiler/apps/utils/replay.py +5 -3
- siliconcompiler/asic.py +120 -0
- siliconcompiler/checklist.py +150 -0
- siliconcompiler/core.py +267 -289
- siliconcompiler/flowgraph.py +803 -515
- siliconcompiler/fpga.py +84 -0
- siliconcompiler/metric.py +420 -0
- siliconcompiler/optimizer/vizier.py +2 -3
- siliconcompiler/package/__init__.py +29 -6
- siliconcompiler/pdk.py +415 -0
- siliconcompiler/record.py +449 -0
- siliconcompiler/remote/client.py +6 -3
- siliconcompiler/remote/schema.py +116 -112
- siliconcompiler/remote/server.py +3 -5
- siliconcompiler/report/dashboard/cli/__init__.py +13 -722
- siliconcompiler/report/dashboard/cli/board.py +895 -0
- siliconcompiler/report/dashboard/web/__init__.py +10 -10
- siliconcompiler/report/dashboard/web/components/__init__.py +5 -4
- siliconcompiler/report/dashboard/web/components/flowgraph.py +3 -3
- siliconcompiler/report/dashboard/web/components/graph.py +6 -3
- siliconcompiler/report/dashboard/web/state.py +1 -1
- siliconcompiler/report/dashboard/web/utils/__init__.py +4 -3
- siliconcompiler/report/html_report.py +2 -3
- siliconcompiler/report/report.py +13 -7
- siliconcompiler/report/summary_image.py +1 -1
- siliconcompiler/report/summary_table.py +3 -3
- siliconcompiler/report/utils.py +11 -10
- siliconcompiler/scheduler/__init__.py +145 -280
- siliconcompiler/scheduler/run_node.py +2 -1
- siliconcompiler/scheduler/send_messages.py +4 -4
- siliconcompiler/scheduler/slurm.py +2 -2
- siliconcompiler/schema/__init__.py +19 -2
- siliconcompiler/schema/baseschema.py +493 -0
- siliconcompiler/schema/cmdlineschema.py +250 -0
- siliconcompiler/{sphinx_ext → schema/docs}/__init__.py +3 -1
- siliconcompiler/{sphinx_ext → schema/docs}/dynamicgen.py +63 -81
- siliconcompiler/{sphinx_ext → schema/docs}/schemagen.py +73 -85
- siliconcompiler/{sphinx_ext → schema/docs}/utils.py +12 -13
- siliconcompiler/schema/editableschema.py +136 -0
- siliconcompiler/schema/journalingschema.py +238 -0
- siliconcompiler/schema/namedschema.py +41 -0
- siliconcompiler/schema/packageschema.py +101 -0
- siliconcompiler/schema/parameter.py +791 -0
- siliconcompiler/schema/parametertype.py +323 -0
- siliconcompiler/schema/parametervalue.py +736 -0
- siliconcompiler/schema/safeschema.py +37 -0
- siliconcompiler/schema/schema_cfg.py +109 -1789
- siliconcompiler/schema/utils.py +5 -68
- siliconcompiler/schema_obj.py +119 -0
- siliconcompiler/tool.py +1308 -0
- siliconcompiler/tools/_common/__init__.py +6 -10
- siliconcompiler/tools/_common/sdc/sc_constraints.sdc +1 -1
- siliconcompiler/tools/bluespec/convert.py +7 -7
- siliconcompiler/tools/builtin/_common.py +1 -1
- siliconcompiler/tools/builtin/concatenate.py +2 -2
- siliconcompiler/tools/builtin/minimum.py +1 -1
- siliconcompiler/tools/builtin/mux.py +2 -1
- siliconcompiler/tools/builtin/nop.py +1 -1
- siliconcompiler/tools/builtin/verify.py +6 -4
- siliconcompiler/tools/chisel/convert.py +4 -4
- siliconcompiler/tools/genfasm/bitstream.py +3 -3
- siliconcompiler/tools/ghdl/convert.py +1 -1
- siliconcompiler/tools/icarus/compile.py +4 -4
- siliconcompiler/tools/icepack/bitstream.py +6 -1
- siliconcompiler/tools/klayout/convert_drc_db.py +5 -0
- siliconcompiler/tools/klayout/klayout_export.py +0 -1
- siliconcompiler/tools/klayout/klayout_utils.py +3 -10
- siliconcompiler/tools/nextpnr/apr.py +6 -1
- siliconcompiler/tools/nextpnr/nextpnr.py +4 -4
- siliconcompiler/tools/openroad/_apr.py +13 -0
- siliconcompiler/tools/openroad/rdlroute.py +3 -3
- siliconcompiler/tools/openroad/scripts/apr/postamble.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +5 -5
- siliconcompiler/tools/openroad/scripts/apr/sc_antenna_repair.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_detailed_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_endcap_tapcell_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_fillercell_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_fillmetal_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_global_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +3 -3
- siliconcompiler/tools/openroad/scripts/apr/sc_metrics.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_pin_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +57 -1
- siliconcompiler/tools/openroad/scripts/common/screenshot.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/common/write_images.tcl +28 -3
- siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -3
- siliconcompiler/tools/openroad/scripts/sc_show.tcl +6 -6
- siliconcompiler/tools/slang/__init__.py +10 -10
- siliconcompiler/tools/surelog/parse.py +4 -4
- siliconcompiler/tools/sv2v/convert.py +20 -3
- siliconcompiler/tools/verilator/compile.py +2 -2
- siliconcompiler/tools/verilator/verilator.py +3 -3
- siliconcompiler/tools/vpr/place.py +1 -1
- siliconcompiler/tools/vpr/route.py +4 -4
- siliconcompiler/tools/vpr/screenshot.py +1 -1
- siliconcompiler/tools/vpr/show.py +5 -5
- siliconcompiler/tools/vpr/vpr.py +24 -24
- siliconcompiler/tools/xdm/convert.py +2 -2
- siliconcompiler/tools/xyce/simulate.py +1 -1
- siliconcompiler/tools/yosys/sc_synth_asic.tcl +74 -68
- siliconcompiler/tools/yosys/syn_asic.py +2 -2
- siliconcompiler/toolscripts/_tools.json +7 -7
- siliconcompiler/toolscripts/ubuntu22/install-vpr.sh +0 -2
- siliconcompiler/toolscripts/ubuntu24/install-vpr.sh +0 -2
- siliconcompiler/utils/__init__.py +8 -112
- siliconcompiler/utils/flowgraph.py +339 -0
- siliconcompiler/{issue.py → utils/issue.py} +4 -3
- siliconcompiler/utils/logging.py +1 -2
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/METADATA +9 -8
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/RECORD +151 -134
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/entry_points.txt +8 -8
- siliconcompiler/schema/schema_obj.py +0 -1936
- siliconcompiler/toolscripts/ubuntu20/install-vpr.sh +0 -29
- siliconcompiler/toolscripts/ubuntu20/install-yosys-parmys.sh +0 -61
- /siliconcompiler/{templates → data/templates}/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/email/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/email/general.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/email/summary.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/issue/README.txt +0 -0
- /siliconcompiler/{templates → data/templates}/issue/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/issue/run.sh +0 -0
- /siliconcompiler/{templates → data/templates}/replay/replay.py.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/replay/replay.sh.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/replay/requirements.txt +0 -0
- /siliconcompiler/{templates → data/templates}/replay/setup.sh +0 -0
- /siliconcompiler/{templates → data/templates}/report/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap.min.css +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap.min.js +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap_LICENSE.md +0 -0
- /siliconcompiler/{templates → data/templates}/report/sc_report.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/slurm/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/slurm/run.sh +0 -0
- /siliconcompiler/{templates → data/templates}/tcl/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/tcl/manifest.tcl.j2 +0 -0
- /siliconcompiler/{units.py → utils/units.py} +0 -0
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/top_level.txt +0 -0
siliconcompiler/core.py
CHANGED
|
@@ -11,13 +11,16 @@ import logging
|
|
|
11
11
|
import hashlib
|
|
12
12
|
import shutil
|
|
13
13
|
import importlib
|
|
14
|
-
import inspect
|
|
15
14
|
import textwrap
|
|
16
15
|
import graphviz
|
|
17
16
|
import codecs
|
|
18
|
-
import
|
|
17
|
+
import csv
|
|
18
|
+
import yaml
|
|
19
19
|
from inspect import getfullargspec
|
|
20
|
-
from siliconcompiler
|
|
20
|
+
from siliconcompiler import Schema
|
|
21
|
+
from siliconcompiler.schema import SCHEMA_VERSION, PerNode, JournalingSchema, EditableSchema
|
|
22
|
+
from siliconcompiler.schema.parametertype import NodeType
|
|
23
|
+
from siliconcompiler.schema.parametervalue import FileNodeValue, PathNodeValue
|
|
21
24
|
from siliconcompiler.schema import utils as schema_utils
|
|
22
25
|
from siliconcompiler import utils
|
|
23
26
|
from siliconcompiler.utils.logging import SCColorLoggerFormatter, \
|
|
@@ -34,12 +37,13 @@ from siliconcompiler.report.dashboard import DashboardType
|
|
|
34
37
|
from siliconcompiler import package as sc_package
|
|
35
38
|
import glob
|
|
36
39
|
from siliconcompiler.scheduler import run as sc_runner
|
|
37
|
-
from siliconcompiler.flowgraph import
|
|
38
|
-
_get_pruned_node_inputs,
|
|
40
|
+
from siliconcompiler.utils.flowgraph import nodes_to_execute, \
|
|
41
|
+
_get_pruned_node_inputs, \
|
|
39
42
|
_get_flowgraph_execution_order, _check_flowgraph_io, \
|
|
40
43
|
_get_flowgraph_information
|
|
41
44
|
from siliconcompiler.tools._common import get_tool_task
|
|
42
45
|
from types import FunctionType, ModuleType
|
|
46
|
+
from siliconcompiler.flowgraph import RuntimeFlowgraph
|
|
43
47
|
|
|
44
48
|
|
|
45
49
|
class Chip:
|
|
@@ -388,7 +392,7 @@ class Chip:
|
|
|
388
392
|
|
|
389
393
|
is_list = '[' in paramtype
|
|
390
394
|
|
|
391
|
-
for vals, step, index in self.schema.
|
|
395
|
+
for vals, step, index in self.schema.get(*key, field=None).getvalues():
|
|
392
396
|
if not vals:
|
|
393
397
|
continue
|
|
394
398
|
if not self.get(*key, field='pernode').is_never():
|
|
@@ -397,9 +401,10 @@ class Chip:
|
|
|
397
401
|
if index is None:
|
|
398
402
|
index = Schema.GLOBAL_KEY
|
|
399
403
|
|
|
404
|
+
packages = self.get(*key, field='package', step=step, index=index)
|
|
400
405
|
if not is_list:
|
|
401
406
|
vals = [vals]
|
|
402
|
-
|
|
407
|
+
packages = [packages]
|
|
403
408
|
if len(packages) == len(vals):
|
|
404
409
|
continue
|
|
405
410
|
|
|
@@ -476,7 +481,6 @@ class Chip:
|
|
|
476
481
|
progname=progname,
|
|
477
482
|
description=description,
|
|
478
483
|
switchlist=switchlist,
|
|
479
|
-
input_map=input_map,
|
|
480
484
|
additional_args=additional_args,
|
|
481
485
|
version=_metadata.version,
|
|
482
486
|
print_banner=print_banner,
|
|
@@ -659,11 +663,10 @@ class Chip:
|
|
|
659
663
|
|
|
660
664
|
elif isinstance(use_module, (Library, Chip)):
|
|
661
665
|
self._loaded_modules['libs'].append(use_module.design)
|
|
662
|
-
cfg = use_module.schema.cfg
|
|
663
666
|
keep_inputs = True
|
|
664
667
|
if not isinstance(use_module, Library):
|
|
665
668
|
keep_inputs = False
|
|
666
|
-
self.__import_library(use_module.design,
|
|
669
|
+
self.__import_library(use_module.design, use_module,
|
|
667
670
|
keep_input=keep_inputs)
|
|
668
671
|
|
|
669
672
|
is_auto_enable = getattr(use_module, 'is_auto_enable', None)
|
|
@@ -677,26 +680,13 @@ class Chip:
|
|
|
677
680
|
raise ValueError(f"{module_name} returned an object with an "
|
|
678
681
|
f"unsupported type: {class_name}")
|
|
679
682
|
|
|
680
|
-
def __import_data_sources(self,
|
|
681
|
-
if 'package'
|
|
683
|
+
def __import_data_sources(self, schema):
|
|
684
|
+
if not schema.valid('package', 'source'):
|
|
682
685
|
return
|
|
683
686
|
|
|
684
|
-
for source
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if 'path' not in config or \
|
|
689
|
-
Schema.GLOBAL_KEY not in config['path']['node'] or \
|
|
690
|
-
Schema.GLOBAL_KEY not in config['path']['node'][Schema.GLOBAL_KEY]:
|
|
691
|
-
continue
|
|
692
|
-
|
|
693
|
-
path = config['path']['node'][Schema.GLOBAL_KEY][Schema.GLOBAL_KEY]['value']
|
|
694
|
-
|
|
695
|
-
ref = None
|
|
696
|
-
if 'ref' in config and \
|
|
697
|
-
Schema.GLOBAL_KEY in config['ref']['node'] and \
|
|
698
|
-
Schema.GLOBAL_KEY in config['ref']['node'][Schema.GLOBAL_KEY]:
|
|
699
|
-
ref = config['ref']['node'][Schema.GLOBAL_KEY][Schema.GLOBAL_KEY]['value']
|
|
687
|
+
for source in schema.getkeys('package', 'source'):
|
|
688
|
+
path = schema.get('package', 'source', source, 'path')
|
|
689
|
+
ref = schema.get('package', 'source', source, 'ref')
|
|
700
690
|
|
|
701
691
|
self.register_source(
|
|
702
692
|
name=source,
|
|
@@ -714,15 +704,24 @@ class Chip:
|
|
|
714
704
|
|
|
715
705
|
importname = module.design
|
|
716
706
|
|
|
717
|
-
|
|
707
|
+
if hasattr(module, 'schema'):
|
|
708
|
+
module = module.schema
|
|
718
709
|
|
|
719
|
-
if importname
|
|
710
|
+
if self.valid(group, importname):
|
|
720
711
|
self.logger.warning(f'Overwriting existing {group} {importname}')
|
|
721
|
-
del src_cfg[importname]
|
|
722
712
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
713
|
+
try:
|
|
714
|
+
insert_schema = EditableSchema(module).search(group, importname)
|
|
715
|
+
except KeyError:
|
|
716
|
+
self.logger.warning(f'{group} {importname} is not valid')
|
|
717
|
+
return
|
|
718
|
+
|
|
719
|
+
EditableSchema(self.schema).insert(
|
|
720
|
+
group,
|
|
721
|
+
importname,
|
|
722
|
+
insert_schema,
|
|
723
|
+
clobber=True)
|
|
724
|
+
self.__import_data_sources(module)
|
|
726
725
|
|
|
727
726
|
###########################################################################
|
|
728
727
|
def help(self, *keypath):
|
|
@@ -745,13 +744,15 @@ class Chip:
|
|
|
745
744
|
|
|
746
745
|
# Fetch Values
|
|
747
746
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
747
|
+
param = self.get(*keypath, field=None)
|
|
748
|
+
|
|
749
|
+
description = param.get(field='shorthelp')
|
|
750
|
+
typestr = param.get(field='type')
|
|
751
|
+
switchstr = str(param.get(field='switch'))
|
|
752
|
+
defstr = str(param.default.get())
|
|
753
|
+
requirement = str(param.get(field='require'))
|
|
754
|
+
helpstr = param.get(field='help')
|
|
755
|
+
example = param.get(field='example')
|
|
755
756
|
|
|
756
757
|
examplestr = ("\nExamples: " + example[0] + ''.join(
|
|
757
758
|
["\n " + ex for ex in example[1:]]))
|
|
@@ -809,9 +810,12 @@ class Chip:
|
|
|
809
810
|
>>> check = chip.valid('metric', 'foo', '0', 'tasktime', default_valid=True)
|
|
810
811
|
Returns True, even if "foo" and "0" aren't in current configuration.
|
|
811
812
|
"""
|
|
813
|
+
if job:
|
|
814
|
+
return self.schema.history(job).valid(*keypath,
|
|
815
|
+
default_valid=default_valid,
|
|
816
|
+
check_complete=check_complete)
|
|
812
817
|
return self.schema.valid(*keypath,
|
|
813
818
|
default_valid=default_valid,
|
|
814
|
-
job=job,
|
|
815
819
|
check_complete=check_complete)
|
|
816
820
|
|
|
817
821
|
###########################################################################
|
|
@@ -851,7 +855,7 @@ class Chip:
|
|
|
851
855
|
strict = self.schema.get('option', 'strict')
|
|
852
856
|
if field == 'value' and strict:
|
|
853
857
|
pernode = self.schema.get(*keypath, field='pernode')
|
|
854
|
-
if pernode ==
|
|
858
|
+
if pernode == PerNode.OPTIONAL and \
|
|
855
859
|
(step is None or index is None) and \
|
|
856
860
|
(Schema.GLOBAL_KEY not in (step, index)): # allow explicit access to global
|
|
857
861
|
self.error(
|
|
@@ -861,7 +865,10 @@ class Chip:
|
|
|
861
865
|
)
|
|
862
866
|
return None
|
|
863
867
|
|
|
864
|
-
|
|
868
|
+
if job:
|
|
869
|
+
return self.schema.history(job).get(*keypath, field=field, step=step, index=index)
|
|
870
|
+
|
|
871
|
+
return self.schema.get(*keypath, field=field, step=step, index=index)
|
|
865
872
|
except (ValueError, TypeError) as e:
|
|
866
873
|
self.error(str(e))
|
|
867
874
|
return None
|
|
@@ -894,7 +901,10 @@ class Chip:
|
|
|
894
901
|
self.logger.debug('Getting all schema parameter keys.')
|
|
895
902
|
|
|
896
903
|
try:
|
|
897
|
-
|
|
904
|
+
if job:
|
|
905
|
+
return self.schema.history(job).getkeys(*keypath)
|
|
906
|
+
|
|
907
|
+
return self.schema.getkeys(*keypath)
|
|
898
908
|
except (ValueError, TypeError) as e:
|
|
899
909
|
self.error(str(e))
|
|
900
910
|
return None
|
|
@@ -937,23 +947,17 @@ class Chip:
|
|
|
937
947
|
return None
|
|
938
948
|
|
|
939
949
|
###########################################################################
|
|
940
|
-
def __add_set_package(self,
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
if add:
|
|
952
|
-
self.schema.add(*keypath, package, field='package',
|
|
953
|
-
step=step, index=index)
|
|
954
|
-
else:
|
|
955
|
-
self.schema.set(*keypath, package, field='package',
|
|
956
|
-
step=step, index=index, clobber=clobber)
|
|
950
|
+
def __add_set_package(self, value_success, package):
|
|
951
|
+
if not isinstance(value_success, (list, tuple)):
|
|
952
|
+
value_success = [value_success]
|
|
953
|
+
if not isinstance(package, (list, tuple)):
|
|
954
|
+
package = [package]
|
|
955
|
+
if len(value_success) != len(package):
|
|
956
|
+
package = len(value_success) * package
|
|
957
|
+
|
|
958
|
+
for val, package in zip(value_success, package):
|
|
959
|
+
if val.type in ('file', 'dir'):
|
|
960
|
+
val.set(package, field='package')
|
|
957
961
|
|
|
958
962
|
###########################################################################
|
|
959
963
|
def set(self, *args, field='value', clobber=True, step=None, index=None, package=None):
|
|
@@ -999,8 +1003,8 @@ class Chip:
|
|
|
999
1003
|
try:
|
|
1000
1004
|
value_success = self.schema.set(*keypath, value, field=field, clobber=clobber,
|
|
1001
1005
|
step=step, index=index)
|
|
1002
|
-
if field == 'value' and value_success:
|
|
1003
|
-
self.__add_set_package(
|
|
1006
|
+
if field == 'value' and value_success and package:
|
|
1007
|
+
self.__add_set_package(value_success, package)
|
|
1004
1008
|
|
|
1005
1009
|
except (ValueError, TypeError) as e:
|
|
1006
1010
|
self.error(e)
|
|
@@ -1086,8 +1090,8 @@ class Chip:
|
|
|
1086
1090
|
try:
|
|
1087
1091
|
value_success = self.schema.add(*args, field=field, step=step, index=index)
|
|
1088
1092
|
|
|
1089
|
-
if field == 'value' and value_success:
|
|
1090
|
-
self.__add_set_package(
|
|
1093
|
+
if field == 'value' and value_success and package:
|
|
1094
|
+
self.__add_set_package(value_success, package)
|
|
1091
1095
|
except (ValueError, TypeError) as e:
|
|
1092
1096
|
self.error(str(e))
|
|
1093
1097
|
|
|
@@ -1109,8 +1113,10 @@ class Chip:
|
|
|
1109
1113
|
package_name = f'flist-{os.path.basename(filename)}'
|
|
1110
1114
|
package_dir = os.path.dirname(os.path.abspath(filename))
|
|
1111
1115
|
|
|
1116
|
+
env_vars = utils.get_env_vars(self, None, None)
|
|
1117
|
+
|
|
1112
1118
|
def __make_path(rel, path):
|
|
1113
|
-
path =
|
|
1119
|
+
path = PathNodeValue.resolve_env_vars(path, envvars=env_vars)
|
|
1114
1120
|
if os.path.isabs(path):
|
|
1115
1121
|
if path.startswith(rel):
|
|
1116
1122
|
return os.path.relpath(path, rel), package_name
|
|
@@ -1281,7 +1287,7 @@ class Chip:
|
|
|
1281
1287
|
"""
|
|
1282
1288
|
strict = self.get('option', 'strict')
|
|
1283
1289
|
pernode = self.get(*keypath, field='pernode')
|
|
1284
|
-
if strict and pernode ==
|
|
1290
|
+
if strict and pernode == PerNode.OPTIONAL and (step is None or index is None):
|
|
1285
1291
|
self.error(
|
|
1286
1292
|
f"Invalid args to find_files() of keypath {keypath}: step and "
|
|
1287
1293
|
"index are required for reading from this parameter while "
|
|
@@ -1313,7 +1319,9 @@ class Chip:
|
|
|
1313
1319
|
"""Internal find_files() that allows you to skip step/index for optional
|
|
1314
1320
|
params, regardless of [option, strict]."""
|
|
1315
1321
|
|
|
1316
|
-
|
|
1322
|
+
param = self.get(*keypath, field=None, job=job)
|
|
1323
|
+
|
|
1324
|
+
paramtype = param.get(field='type')
|
|
1317
1325
|
|
|
1318
1326
|
if 'file' not in paramtype and 'dir' not in paramtype:
|
|
1319
1327
|
self.error('Can only call find_files on file or dir types')
|
|
@@ -1321,15 +1329,15 @@ class Chip:
|
|
|
1321
1329
|
|
|
1322
1330
|
is_list = bool(re.match(r'\[', paramtype))
|
|
1323
1331
|
|
|
1324
|
-
paths =
|
|
1325
|
-
dependencies =
|
|
1326
|
-
|
|
1332
|
+
paths = param.get(step=step, index=index)
|
|
1333
|
+
dependencies = param.get(field='package', step=step, index=index)
|
|
1334
|
+
|
|
1327
1335
|
# Convert to list if we have scalar
|
|
1328
1336
|
if not is_list:
|
|
1329
1337
|
# Dependencies are always specified as list with default []
|
|
1330
1338
|
# If paths is a scalar we convert the default [] to [None]
|
|
1331
1339
|
# to have a matching list with one element
|
|
1332
|
-
if dependencies
|
|
1340
|
+
if not dependencies:
|
|
1333
1341
|
dependencies = [None]
|
|
1334
1342
|
paths = [paths]
|
|
1335
1343
|
|
|
@@ -1339,7 +1347,6 @@ class Chip:
|
|
|
1339
1347
|
dependencies = [dependencies[list_index]]
|
|
1340
1348
|
|
|
1341
1349
|
paths = self.__convert_paths_to_posix(paths)
|
|
1342
|
-
dependencies = self.__convert_paths_to_posix(dependencies)
|
|
1343
1350
|
|
|
1344
1351
|
result = []
|
|
1345
1352
|
|
|
@@ -1373,29 +1380,32 @@ class Chip:
|
|
|
1373
1380
|
|
|
1374
1381
|
if search_paths:
|
|
1375
1382
|
search_paths = self.__convert_paths_to_posix(search_paths)
|
|
1383
|
+
else:
|
|
1384
|
+
search_paths = [self.cwd]
|
|
1376
1385
|
|
|
1386
|
+
env_vars = utils.get_env_vars(self, step, index)
|
|
1377
1387
|
for (dependency, path) in zip(dependencies, paths):
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
depdendency_path = os.path.abspath(
|
|
1385
|
-
os.path.join(sc_package.path(self, dependency), path))
|
|
1386
|
-
if os.path.exists(depdendency_path):
|
|
1387
|
-
result.append(depdendency_path)
|
|
1388
|
+
faux_param = FileNodeValue()
|
|
1389
|
+
faux_param.set(path)
|
|
1390
|
+
try:
|
|
1391
|
+
if dependency:
|
|
1392
|
+
faux_param.set(dependency, field='package')
|
|
1393
|
+
faux_search = [os.path.abspath(os.path.join(sc_package.path(self, dependency)))]
|
|
1388
1394
|
else:
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1395
|
+
faux_search = search_paths
|
|
1396
|
+
resolved = faux_param.resolve_path(
|
|
1397
|
+
envvars=env_vars,
|
|
1398
|
+
search=faux_search,
|
|
1399
|
+
collection_dir=collection_dir)
|
|
1400
|
+
except FileNotFoundError:
|
|
1401
|
+
resolved = None
|
|
1402
|
+
if not missing_ok:
|
|
1403
|
+
if dependency:
|
|
1404
|
+
self.error(f'Could not find {path} in {dependency}. [{",".join(keypath)}]')
|
|
1405
|
+
else:
|
|
1406
|
+
self.error(f'Could not find {path}. [{",".join(keypath)}]')
|
|
1407
|
+
|
|
1408
|
+
result.append(resolved)
|
|
1399
1409
|
|
|
1400
1410
|
if self._relative_path and not abs_path_only:
|
|
1401
1411
|
rel_result = []
|
|
@@ -1408,6 +1418,8 @@ class Chip:
|
|
|
1408
1418
|
|
|
1409
1419
|
# Convert back to scalar if that was original type
|
|
1410
1420
|
if not is_list:
|
|
1421
|
+
if not result:
|
|
1422
|
+
return None
|
|
1411
1423
|
return result[0]
|
|
1412
1424
|
|
|
1413
1425
|
return result
|
|
@@ -1420,33 +1432,20 @@ class Chip:
|
|
|
1420
1432
|
|
|
1421
1433
|
Returns none if not found
|
|
1422
1434
|
"""
|
|
1423
|
-
if not
|
|
1435
|
+
if not collected_dir:
|
|
1424
1436
|
return None
|
|
1425
1437
|
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1438
|
+
faux_param = FileNodeValue()
|
|
1439
|
+
faux_param.set(path)
|
|
1440
|
+
faux_param.set(package, field='package')
|
|
1429
1441
|
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
n += 1
|
|
1436
|
-
basename = str(pathlib.PurePosixPath(*path_paths[0:n]))
|
|
1437
|
-
endname = str(pathlib.PurePosixPath(*path_paths[n:]))
|
|
1438
|
-
|
|
1439
|
-
import_name = utils.get_hashed_filename(basename, package=package)
|
|
1440
|
-
if import_name not in collected_files:
|
|
1441
|
-
continue
|
|
1442
|
-
|
|
1443
|
-
abspath = os.path.join(collected_dir, import_name)
|
|
1444
|
-
if endname:
|
|
1445
|
-
abspath = os.path.join(abspath, endname)
|
|
1446
|
-
abspath = os.path.abspath(abspath)
|
|
1447
|
-
if os.path.exists(abspath):
|
|
1448
|
-
return abspath
|
|
1442
|
+
try:
|
|
1443
|
+
resolved = faux_param.resolve_path(collection_dir=collected_dir)
|
|
1444
|
+
except FileNotFoundError:
|
|
1445
|
+
return None
|
|
1449
1446
|
|
|
1447
|
+
if resolved.startswith(collected_dir):
|
|
1448
|
+
return resolved
|
|
1450
1449
|
return None
|
|
1451
1450
|
|
|
1452
1451
|
def find_node_file(self, path, step, jobname=None, index='0'):
|
|
@@ -1530,7 +1529,7 @@ class Chip:
|
|
|
1530
1529
|
# only do something if type is file or dir
|
|
1531
1530
|
continue
|
|
1532
1531
|
|
|
1533
|
-
values = self.schema.
|
|
1532
|
+
values = self.schema.get(*keypath, field=None).getvalues()
|
|
1534
1533
|
for value, step, index in values:
|
|
1535
1534
|
if not value:
|
|
1536
1535
|
continue
|
|
@@ -1565,7 +1564,7 @@ class Chip:
|
|
|
1565
1564
|
# exist
|
|
1566
1565
|
continue
|
|
1567
1566
|
|
|
1568
|
-
for check_files, step, index in self.schema.
|
|
1567
|
+
for check_files, step, index in self.schema.get(*keypath, field=None).getvalues():
|
|
1569
1568
|
if not check_files:
|
|
1570
1569
|
continue
|
|
1571
1570
|
|
|
@@ -1652,7 +1651,7 @@ class Chip:
|
|
|
1652
1651
|
lib_node_check.append((step, None))
|
|
1653
1652
|
lib_node_check.extend(nodes)
|
|
1654
1653
|
for lib_key in libs_to_check:
|
|
1655
|
-
for val, step, index in self.schema.
|
|
1654
|
+
for val, step, index in self.schema.get(*lib_key, field=None).getvalues():
|
|
1656
1655
|
if (step, index) in lib_node_check:
|
|
1657
1656
|
libraries.update(val)
|
|
1658
1657
|
|
|
@@ -1666,9 +1665,8 @@ class Chip:
|
|
|
1666
1665
|
for key in allkeys:
|
|
1667
1666
|
keypath = ",".join(key)
|
|
1668
1667
|
if 'default' not in key and 'history' not in key and 'library' not in key:
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
if key_empty and requirement:
|
|
1668
|
+
param = self.get(*key, field=None)
|
|
1669
|
+
if param.is_empty() and param.get(field='require'):
|
|
1672
1670
|
error = True
|
|
1673
1671
|
self.logger.error(f"Global requirement missing for [{keypath}].")
|
|
1674
1672
|
|
|
@@ -1710,12 +1708,12 @@ class Chip:
|
|
|
1710
1708
|
step=step, index=index)
|
|
1711
1709
|
for item in all_required:
|
|
1712
1710
|
keypath = item.split(',')
|
|
1713
|
-
if self.schema.
|
|
1711
|
+
if self.schema.get(*keypath, field=None).is_empty():
|
|
1714
1712
|
error = True
|
|
1715
1713
|
self.logger.error(f"Value empty for {keypath} for {tool}.")
|
|
1716
1714
|
|
|
1717
1715
|
task_run = getattr(task_module, 'run', None)
|
|
1718
|
-
if self.schema.
|
|
1716
|
+
if self.schema.get('tool', tool, 'exe', field=None).is_empty() and not task_run:
|
|
1719
1717
|
error = True
|
|
1720
1718
|
self.logger.error(f'No executable or run() function specified for {tool}/{task}')
|
|
1721
1719
|
|
|
@@ -1743,26 +1741,8 @@ class Chip:
|
|
|
1743
1741
|
Loads the file mychip.json into the current Chip object.
|
|
1744
1742
|
"""
|
|
1745
1743
|
|
|
1746
|
-
# Read from file into new schema object
|
|
1747
|
-
schema = Schema(manifest=filename, logger=self.logger)
|
|
1748
|
-
|
|
1749
1744
|
# Merge data in schema with Chip configuration
|
|
1750
|
-
self.schema.
|
|
1751
|
-
|
|
1752
|
-
# Read history, if we're not already reading into a job
|
|
1753
|
-
if 'history' in schema.cfg and not job:
|
|
1754
|
-
for historic_job in schema.cfg['history'].keys():
|
|
1755
|
-
self.schema.merge_manifest(schema.history(historic_job),
|
|
1756
|
-
job=historic_job,
|
|
1757
|
-
clear=clear,
|
|
1758
|
-
clobber=clobber)
|
|
1759
|
-
|
|
1760
|
-
# TODO: better way to handle this?
|
|
1761
|
-
if 'library' in schema.cfg:
|
|
1762
|
-
for libname in schema.cfg['library'].keys():
|
|
1763
|
-
self.__import_library(libname, schema.cfg['library'][libname],
|
|
1764
|
-
job=job,
|
|
1765
|
-
clobber=clobber)
|
|
1745
|
+
self.schema.read_manifest(filename)
|
|
1766
1746
|
|
|
1767
1747
|
###########################################################################
|
|
1768
1748
|
def write_manifest(self, filename, prune=False, abspath=False):
|
|
@@ -1796,12 +1776,14 @@ class Chip:
|
|
|
1796
1776
|
if abspath:
|
|
1797
1777
|
schema = self.__abspath()
|
|
1798
1778
|
|
|
1799
|
-
if
|
|
1800
|
-
|
|
1801
|
-
|
|
1779
|
+
if re.search(r'(\.json|\.sup)(\.gz)*$', filepath):
|
|
1780
|
+
schema.write_manifest(filepath)
|
|
1781
|
+
return
|
|
1802
1782
|
|
|
1803
|
-
|
|
1804
|
-
|
|
1783
|
+
tcl_record = False
|
|
1784
|
+
if isinstance(schema, JournalingSchema):
|
|
1785
|
+
tcl_record = "get" in schema.get_journaling_types()
|
|
1786
|
+
schema = schema.get_base_schema()
|
|
1805
1787
|
|
|
1806
1788
|
is_csv = re.search(r'(\.csv)(\.gz)*$', filepath)
|
|
1807
1789
|
|
|
@@ -1817,26 +1799,85 @@ class Chip:
|
|
|
1817
1799
|
|
|
1818
1800
|
# format specific printing
|
|
1819
1801
|
try:
|
|
1820
|
-
if re.search(r'(\.
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1802
|
+
if re.search(r'(\.yaml|\.yml)(\.gz)*$', filepath):
|
|
1803
|
+
class YamlIndentDumper(yaml.Dumper):
|
|
1804
|
+
def increase_indent(self, flow=False, indentless=False):
|
|
1805
|
+
return super().increase_indent(flow=flow, indentless=False)
|
|
1806
|
+
|
|
1807
|
+
fout.write(yaml.dump(schema.getdict(), Dumper=YamlIndentDumper,
|
|
1808
|
+
default_flow_style=False))
|
|
1809
|
+
|
|
1824
1810
|
elif re.search(r'(\.tcl)(\.gz)*$', filepath):
|
|
1825
1811
|
# TCL only gets values associated with the current node.
|
|
1826
1812
|
step = self.get('arg', 'step')
|
|
1827
1813
|
index = self.get('arg', 'index')
|
|
1828
|
-
|
|
1814
|
+
self.__write_tcl(fout,
|
|
1815
|
+
schema,
|
|
1829
1816
|
prefix="dict set sc_cfg",
|
|
1830
1817
|
step=step,
|
|
1831
1818
|
index=index,
|
|
1832
|
-
template=utils.get_file_template('tcl/manifest.tcl.j2')
|
|
1819
|
+
template=utils.get_file_template('tcl/manifest.tcl.j2'),
|
|
1820
|
+
record=tcl_record)
|
|
1833
1821
|
elif is_csv:
|
|
1834
|
-
|
|
1822
|
+
csvwriter = csv.writer(fout)
|
|
1823
|
+
csvwriter.writerow(['Keypath', 'Value'])
|
|
1824
|
+
|
|
1825
|
+
allkeys = schema.allkeys()
|
|
1826
|
+
for key in allkeys:
|
|
1827
|
+
keypath = ','.join(key)
|
|
1828
|
+
param = schema.get(*key, field=None)
|
|
1829
|
+
for value, step, index in param.getvalues():
|
|
1830
|
+
if step is None and index is None:
|
|
1831
|
+
keypath = ','.join(key)
|
|
1832
|
+
elif index is None:
|
|
1833
|
+
keypath = ','.join([*key, step, 'default'])
|
|
1834
|
+
else:
|
|
1835
|
+
keypath = ','.join([*key, step, index])
|
|
1836
|
+
|
|
1837
|
+
if isinstance(value, list):
|
|
1838
|
+
for item in value:
|
|
1839
|
+
csvwriter.writerow([keypath, item])
|
|
1840
|
+
else:
|
|
1841
|
+
csvwriter.writerow([keypath, value])
|
|
1835
1842
|
else:
|
|
1836
1843
|
self.error(f'File format not recognized {filepath}')
|
|
1837
1844
|
finally:
|
|
1838
1845
|
fout.close()
|
|
1839
1846
|
|
|
1847
|
+
def __write_tcl(self, fout, schema,
|
|
1848
|
+
prefix="", step=None, index=None, template=None, record=False):
|
|
1849
|
+
tcl_set_cmds = []
|
|
1850
|
+
for key in sorted(schema.allkeys()):
|
|
1851
|
+
# print out all non default values
|
|
1852
|
+
if 'default' in key:
|
|
1853
|
+
continue
|
|
1854
|
+
|
|
1855
|
+
param = schema.get(*key, field=None)
|
|
1856
|
+
|
|
1857
|
+
# create a TCL dict
|
|
1858
|
+
keystr = ' '.join([NodeType.to_tcl(keypart, 'str') for keypart in key])
|
|
1859
|
+
|
|
1860
|
+
valstr = param.gettcl(step=step, index=index)
|
|
1861
|
+
if valstr is None:
|
|
1862
|
+
continue
|
|
1863
|
+
|
|
1864
|
+
# Ensure empty values get something
|
|
1865
|
+
if valstr == '':
|
|
1866
|
+
valstr = '{}'
|
|
1867
|
+
|
|
1868
|
+
tcl_set_cmds.append(f"{prefix} {keystr} {valstr}")
|
|
1869
|
+
|
|
1870
|
+
if template:
|
|
1871
|
+
fout.write(template.render(manifest_dict='\n'.join(tcl_set_cmds),
|
|
1872
|
+
scroot=os.path.abspath(
|
|
1873
|
+
os.path.join(os.path.dirname(__file__))),
|
|
1874
|
+
record_access=record,
|
|
1875
|
+
record_access_id=Schema._RECORD_ACCESS_IDENTIFIER))
|
|
1876
|
+
else:
|
|
1877
|
+
for cmd in tcl_set_cmds:
|
|
1878
|
+
fout.write(cmd + '\n')
|
|
1879
|
+
fout.write('\n')
|
|
1880
|
+
|
|
1840
1881
|
###########################################################################
|
|
1841
1882
|
def check_checklist(self, standard, items=None,
|
|
1842
1883
|
check_ok=False, verbose=False, require_reports=True):
|
|
@@ -1978,15 +2019,17 @@ class Chip:
|
|
|
1978
2019
|
self.get('tool', tool, 'task', task, 'report', metric, job=job,
|
|
1979
2020
|
step=step, index=index)
|
|
1980
2021
|
|
|
1981
|
-
if
|
|
2022
|
+
if allow_missing_reports and not has_reports:
|
|
1982
2023
|
# No reports available and it is allowed
|
|
1983
2024
|
continue
|
|
1984
2025
|
|
|
2026
|
+
reports = []
|
|
1985
2027
|
try:
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2028
|
+
if has_reports:
|
|
2029
|
+
reports = self.find_files('tool', tool, 'task', task, 'report', metric,
|
|
2030
|
+
job=job,
|
|
2031
|
+
step=step, index=index,
|
|
2032
|
+
missing_ok=not require_reports)
|
|
1990
2033
|
except SiliconCompilerError:
|
|
1991
2034
|
reports = []
|
|
1992
2035
|
continue
|
|
@@ -2022,33 +2065,38 @@ class Chip:
|
|
|
2022
2065
|
return not error
|
|
2023
2066
|
|
|
2024
2067
|
###########################################################################
|
|
2025
|
-
def __import_library(self, libname,
|
|
2068
|
+
def __import_library(self, libname, library, job=None, clobber=True, keep_input=True):
|
|
2026
2069
|
'''Helper to import library with config 'libconfig' as a library
|
|
2027
2070
|
'libname' in current Chip object.'''
|
|
2028
|
-
if job:
|
|
2029
|
-
cfg = self.schema.cfg['history'][job]['library']
|
|
2030
|
-
else:
|
|
2031
|
-
cfg = self.schema.cfg['library']
|
|
2032
|
-
|
|
2033
|
-
if 'library' in libcfg:
|
|
2034
|
-
for sublib_name, sublibcfg in libcfg['library'].items():
|
|
2035
|
-
self.__import_library(sublib_name, sublibcfg,
|
|
2036
|
-
job=job, clobber=clobber, keep_input=keep_input)
|
|
2037
2071
|
|
|
2038
|
-
if libname in
|
|
2072
|
+
if libname in self.schema.getkeys('library'):
|
|
2039
2073
|
if not clobber:
|
|
2040
2074
|
return
|
|
2075
|
+
if hasattr(library, 'schema'):
|
|
2076
|
+
library = library.schema
|
|
2077
|
+
|
|
2078
|
+
try:
|
|
2079
|
+
for sublib in library.getkeys('library'):
|
|
2080
|
+
self.__import_library(sublib,
|
|
2081
|
+
EditableSchema(library).search('library', sublib),
|
|
2082
|
+
job=job, clobber=clobber, keep_input=keep_input)
|
|
2083
|
+
except KeyError:
|
|
2084
|
+
pass
|
|
2041
2085
|
|
|
2042
|
-
self.__import_data_sources(
|
|
2043
|
-
cfg[libname] = {}
|
|
2086
|
+
self.__import_data_sources(library)
|
|
2044
2087
|
|
|
2045
2088
|
# Only keep some sections to avoid recursive bloat
|
|
2046
2089
|
keeps = ['asic', 'design', 'fpga', 'option', 'output', 'package']
|
|
2047
2090
|
if keep_input:
|
|
2048
2091
|
keeps.append('input')
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2092
|
+
|
|
2093
|
+
importlibrary = library.copy()
|
|
2094
|
+
edit_lib = EditableSchema(importlibrary)
|
|
2095
|
+
for section in list(importlibrary.getkeys()):
|
|
2096
|
+
if section not in keeps:
|
|
2097
|
+
edit_lib.remove(section)
|
|
2098
|
+
|
|
2099
|
+
EditableSchema(self.schema).insert("library", libname, importlibrary, clobber=True)
|
|
2052
2100
|
|
|
2053
2101
|
###########################################################################
|
|
2054
2102
|
def write_flowgraph(self, filename, flow=None,
|
|
@@ -2333,6 +2381,8 @@ class Chip:
|
|
|
2333
2381
|
|
|
2334
2382
|
nodes = {}
|
|
2335
2383
|
|
|
2384
|
+
search_schema = EditableSchema(self.schema)
|
|
2385
|
+
|
|
2336
2386
|
def collect_library(root_type, lib, name=None):
|
|
2337
2387
|
if not name:
|
|
2338
2388
|
name = lib.design
|
|
@@ -2371,15 +2421,15 @@ class Chip:
|
|
|
2371
2421
|
|
|
2372
2422
|
for in_lib in lib.get('option', 'library',
|
|
2373
2423
|
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2374
|
-
collect_library("library",
|
|
2424
|
+
collect_library("library", search_schema.search('library', in_lib),
|
|
2375
2425
|
name=in_lib)
|
|
2376
2426
|
for in_lib in lib.get('asic', 'logiclib',
|
|
2377
2427
|
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2378
|
-
collect_library("logiclib",
|
|
2428
|
+
collect_library("logiclib", search_schema.search('library', in_lib),
|
|
2379
2429
|
name=in_lib)
|
|
2380
2430
|
for in_lib in lib.get('asic', 'macrolib',
|
|
2381
2431
|
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2382
|
-
collect_library("macrolib",
|
|
2432
|
+
collect_library("macrolib", search_schema.search('library', in_lib),
|
|
2383
2433
|
name=in_lib)
|
|
2384
2434
|
|
|
2385
2435
|
collect_library("design", self)
|
|
@@ -2417,6 +2467,8 @@ class Chip:
|
|
|
2417
2467
|
all_libraries = self.getkeys('library')
|
|
2418
2468
|
|
|
2419
2469
|
def swap(*key):
|
|
2470
|
+
if not self.schema.valid(*key):
|
|
2471
|
+
return
|
|
2420
2472
|
if step is not None:
|
|
2421
2473
|
r_step = step
|
|
2422
2474
|
r_index = index
|
|
@@ -2432,7 +2484,7 @@ class Chip:
|
|
|
2432
2484
|
list(map(lambda x: new_library if x == org_library else x, val)),
|
|
2433
2485
|
step=r_step, index=r_index)
|
|
2434
2486
|
else:
|
|
2435
|
-
for val, r_step, r_index in self.schema.
|
|
2487
|
+
for val, r_step, r_index in self.schema.get(*key, field=None).getvalues():
|
|
2436
2488
|
if r_step is None:
|
|
2437
2489
|
r_step = Schema.GLOBAL_KEY
|
|
2438
2490
|
if r_index is None:
|
|
@@ -2510,7 +2562,7 @@ class Chip:
|
|
|
2510
2562
|
is_file = re.search('file', leaftype)
|
|
2511
2563
|
if is_dir or is_file:
|
|
2512
2564
|
if self.get(*key, field='copy'):
|
|
2513
|
-
for value, step, index in self.schema.
|
|
2565
|
+
for value, step, index in self.schema.get(*key, field=None).getvalues():
|
|
2514
2566
|
if not value:
|
|
2515
2567
|
continue
|
|
2516
2568
|
packages = self.get(*key, field='package', step=step, index=index)
|
|
@@ -2694,7 +2746,7 @@ class Chip:
|
|
|
2694
2746
|
flowgraph_nodes = [(step, index)]
|
|
2695
2747
|
elif step:
|
|
2696
2748
|
flow = self.get('option', 'flow')
|
|
2697
|
-
flowgraph_nodes =
|
|
2749
|
+
flowgraph_nodes = [(step, index) for index in self.getkeys("flowgraph", flow, step)]
|
|
2698
2750
|
else:
|
|
2699
2751
|
flowgraph_nodes = nodes_to_execute(self)
|
|
2700
2752
|
|
|
@@ -2815,8 +2867,12 @@ class Chip:
|
|
|
2815
2867
|
if check:
|
|
2816
2868
|
# compare previous hash to new hash
|
|
2817
2869
|
oldhash = self.schema.get(*keypath, step=step, index=index, field='filehash')
|
|
2870
|
+
if not isinstance(oldhash, list):
|
|
2871
|
+
oldhash = [oldhash]
|
|
2818
2872
|
check_failed = False
|
|
2819
2873
|
for i, item in enumerate(oldhash):
|
|
2874
|
+
if item is None:
|
|
2875
|
+
continue
|
|
2820
2876
|
if item != hashlist[i]:
|
|
2821
2877
|
self.logger.error(f"Hash mismatch for [{keypath}]")
|
|
2822
2878
|
check_failed = True
|
|
@@ -2829,11 +2885,11 @@ class Chip:
|
|
|
2829
2885
|
set_step = None
|
|
2830
2886
|
set_index = None
|
|
2831
2887
|
pernode = self.get(*keypath, field='pernode')
|
|
2832
|
-
if pernode ==
|
|
2888
|
+
if pernode == PerNode.REQUIRED:
|
|
2833
2889
|
set_step = step
|
|
2834
2890
|
set_index = index
|
|
2835
|
-
elif pernode ==
|
|
2836
|
-
for vals, key_step, key_index in self.schema.
|
|
2891
|
+
elif pernode == PerNode.OPTIONAL:
|
|
2892
|
+
for vals, key_step, key_index in self.schema.get(*keypath, field=None).getvalues():
|
|
2837
2893
|
if key_step == step and key_index == index and vals:
|
|
2838
2894
|
set_step = step
|
|
2839
2895
|
set_index = index
|
|
@@ -2918,9 +2974,12 @@ class Chip:
|
|
|
2918
2974
|
|
|
2919
2975
|
# display whole flowgraph if no from/to specified
|
|
2920
2976
|
flow = self.get('option', 'flow')
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2977
|
+
runtime = RuntimeFlowgraph(
|
|
2978
|
+
self.schema.get("flowgraph", flow, field='schema'),
|
|
2979
|
+
to_steps=self.get('option', 'to'),
|
|
2980
|
+
prune_nodes=self.get('option', 'prune'))
|
|
2981
|
+
_show_summary_table(self, flow, list(runtime.get_nodes()),
|
|
2982
|
+
show_all_indices=show_all_indices)
|
|
2924
2983
|
|
|
2925
2984
|
# dashboard does not generate any data
|
|
2926
2985
|
self.logger.info('Dashboard at "sc-dashboard '
|
|
@@ -3015,40 +3074,15 @@ class Chip:
|
|
|
3015
3074
|
Creates a 'place' task with step='apr_place' and index=0 and binds it to the
|
|
3016
3075
|
'openroad' tool.
|
|
3017
3076
|
'''
|
|
3077
|
+
from siliconcompiler import FlowgraphSchema
|
|
3078
|
+
from siliconcompiler.schema import EditableSchema
|
|
3018
3079
|
|
|
3019
|
-
if
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
index = str(index)
|
|
3024
|
-
|
|
3025
|
-
# Determine task name and module
|
|
3026
|
-
task_module = None
|
|
3027
|
-
if (isinstance(task, str)):
|
|
3028
|
-
task_module = task
|
|
3029
|
-
elif inspect.ismodule(task):
|
|
3030
|
-
task_module = task.__name__
|
|
3031
|
-
self.modules[task_module] = task
|
|
3080
|
+
if not self.schema.valid("flowgraph", flow):
|
|
3081
|
+
graph = FlowgraphSchema(flow)
|
|
3082
|
+
EditableSchema(self.schema).insert("flowgraph", flow, graph)
|
|
3032
3083
|
else:
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
chip=self)
|
|
3036
|
-
|
|
3037
|
-
task_parts = task_module.split('.')
|
|
3038
|
-
if len(task_parts) < 2:
|
|
3039
|
-
raise SiliconCompilerError(
|
|
3040
|
-
f"{task} is not a valid task, it must be associated with a tool '<tool>.<task>'.",
|
|
3041
|
-
chip=self)
|
|
3042
|
-
tool_name, task_name = task_parts[-2:]
|
|
3043
|
-
|
|
3044
|
-
# bind tool to node
|
|
3045
|
-
self.set('flowgraph', flow, step, index, 'tool', tool_name)
|
|
3046
|
-
self.set('flowgraph', flow, step, index, 'task', task_name)
|
|
3047
|
-
self.set('flowgraph', flow, step, index, 'taskmodule', task_module)
|
|
3048
|
-
|
|
3049
|
-
# set default weights
|
|
3050
|
-
for metric in self.getkeys('metric'):
|
|
3051
|
-
self.set('flowgraph', flow, step, index, 'weight', metric, 0)
|
|
3084
|
+
graph = self.schema.get("flowgraph", flow, field="schema")
|
|
3085
|
+
graph.node(step, task, index=index)
|
|
3052
3086
|
|
|
3053
3087
|
###########################################################################
|
|
3054
3088
|
def edge(self, flow, tail, head, tail_index=0, head_index=0):
|
|
@@ -3073,21 +3107,9 @@ class Chip:
|
|
|
3073
3107
|
>>> chip.edge('place', 'cts')
|
|
3074
3108
|
Creates a directed edge from place to cts.
|
|
3075
3109
|
'''
|
|
3076
|
-
head_index = str(head_index)
|
|
3077
|
-
tail_index = str(tail_index)
|
|
3078
|
-
|
|
3079
|
-
for step in (head, tail):
|
|
3080
|
-
if step in (Schema.GLOBAL_KEY, 'default'):
|
|
3081
|
-
self.error(f'Illegal step name: {step} is reserved')
|
|
3082
|
-
return
|
|
3083
|
-
|
|
3084
|
-
tail_node = (tail, tail_index)
|
|
3085
|
-
if tail_node in self.get('flowgraph', flow, head, head_index, 'input'):
|
|
3086
|
-
self.logger.warning(f'Edge from {tail}{tail_index} to {head}{head_index} already '
|
|
3087
|
-
'exists, skipping')
|
|
3088
|
-
return
|
|
3089
3110
|
|
|
3090
|
-
self.
|
|
3111
|
+
graph = self.schema.get("flowgraph", flow, field="schema")
|
|
3112
|
+
graph.edge(tail, head, tail_index=tail_index, head_index=head_index)
|
|
3091
3113
|
|
|
3092
3114
|
###########################################################################
|
|
3093
3115
|
def remove_node(self, flow, step, index=None):
|
|
@@ -3103,34 +3125,8 @@ class Chip:
|
|
|
3103
3125
|
if flow not in self.getkeys('flowgraph'):
|
|
3104
3126
|
raise ValueError(f'{flow} is not in the manifest')
|
|
3105
3127
|
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
if index is None:
|
|
3110
|
-
# Iterate over all indexes
|
|
3111
|
-
for index in self.getkeys('flowgraph', flow, step):
|
|
3112
|
-
self.remove_node(flow, step, index)
|
|
3113
|
-
return
|
|
3114
|
-
|
|
3115
|
-
index = str(index)
|
|
3116
|
-
if index not in self.getkeys('flowgraph', flow, step):
|
|
3117
|
-
raise ValueError(f'{index} is not a valid index for {step} in {flow}')
|
|
3118
|
-
|
|
3119
|
-
# Save input edges
|
|
3120
|
-
node = (step, index)
|
|
3121
|
-
node_inputs = self.get('flowgraph', flow, step, index, 'input')
|
|
3122
|
-
self.remove('flowgraph', flow, step, index)
|
|
3123
|
-
|
|
3124
|
-
if len(self.getkeys('flowgraph', flow, step)) == 0:
|
|
3125
|
-
self.remove('flowgraph', flow, step)
|
|
3126
|
-
|
|
3127
|
-
for flow_step in self.getkeys('flowgraph', flow):
|
|
3128
|
-
for flow_index in self.getkeys('flowgraph', flow, flow_step):
|
|
3129
|
-
inputs = self.get('flowgraph', flow, flow_step, flow_index, 'input')
|
|
3130
|
-
if node in inputs:
|
|
3131
|
-
inputs = [inode for inode in inputs if inode != node]
|
|
3132
|
-
inputs.extend(node_inputs)
|
|
3133
|
-
self.set('flowgraph', flow, flow_step, flow_index, 'input', set(inputs))
|
|
3128
|
+
graph = self.schema.get("flowgraph", flow, field="schema")
|
|
3129
|
+
graph.remove_node(step, index=index)
|
|
3134
3130
|
|
|
3135
3131
|
###########################################################################
|
|
3136
3132
|
def graph(self, flow, subflow, name=None):
|
|
@@ -3146,27 +3142,9 @@ class Chip:
|
|
|
3146
3142
|
>>> chip.graph('asicflow')
|
|
3147
3143
|
Instantiates a flow named 'asicflow'.
|
|
3148
3144
|
'''
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
newstep = step
|
|
3153
|
-
else:
|
|
3154
|
-
newstep = name + "." + step
|
|
3155
|
-
|
|
3156
|
-
for keys in self.allkeys('flowgraph', subflow, step):
|
|
3157
|
-
val = self.get('flowgraph', subflow, step, *keys)
|
|
3158
|
-
self.set('flowgraph', flow, newstep, *keys, val)
|
|
3159
|
-
|
|
3160
|
-
if name is None:
|
|
3161
|
-
continue
|
|
3162
|
-
|
|
3163
|
-
for index in self.getkeys('flowgraph', flow, newstep):
|
|
3164
|
-
# rename inputs
|
|
3165
|
-
all_inputs = self.get('flowgraph', flow, newstep, index, 'input')
|
|
3166
|
-
self.set('flowgraph', flow, newstep, index, 'input', [])
|
|
3167
|
-
for in_step, in_index in all_inputs:
|
|
3168
|
-
newin = name + "." + in_step
|
|
3169
|
-
self.add('flowgraph', flow, newstep, index, 'input', (newin, in_index))
|
|
3145
|
+
graph = self.schema.get("flowgraph", flow, field="schema")
|
|
3146
|
+
subgraph = self.schema.get("flowgraph", subflow, field="schema")
|
|
3147
|
+
graph.graph(subgraph, name=name)
|
|
3170
3148
|
|
|
3171
3149
|
###########################################################################
|
|
3172
3150
|
def run(self, raise_exception=False):
|
|
@@ -3334,7 +3312,7 @@ class Chip:
|
|
|
3334
3312
|
self.set('option', 'jobname', f'_{taskname}_{sc_job}_{sc_step}{sc_index}', clobber=True)
|
|
3335
3313
|
|
|
3336
3314
|
# Setup in step/index variables
|
|
3337
|
-
for
|
|
3315
|
+
for step, index in self.get("flowgraph", "showflow", field="schema").get_nodes():
|
|
3338
3316
|
if step != taskname:
|
|
3339
3317
|
continue
|
|
3340
3318
|
show_tool, _ = get_tool_task(self, step, index, flow='showflow')
|
|
@@ -3356,7 +3334,8 @@ class Chip:
|
|
|
3356
3334
|
try:
|
|
3357
3335
|
self.run(raise_exception=True)
|
|
3358
3336
|
if screenshot:
|
|
3359
|
-
step, index =
|
|
3337
|
+
step, index = self.schema.get("flowgraph", 'showflow',
|
|
3338
|
+
field="schema").get_exit_nodes()[0]
|
|
3360
3339
|
success = self.find_result('png', step=step, index=index)
|
|
3361
3340
|
else:
|
|
3362
3341
|
success = True
|
|
@@ -3434,8 +3413,8 @@ class Chip:
|
|
|
3434
3413
|
if hasattr(self, 'logger'):
|
|
3435
3414
|
self.logger.error(msg)
|
|
3436
3415
|
|
|
3437
|
-
step = self.get('arg', 'step')
|
|
3438
|
-
index = self.get('arg', 'index')
|
|
3416
|
+
step = self.schema.get('arg', 'step')
|
|
3417
|
+
index = self.schema.get('arg', 'index')
|
|
3439
3418
|
if self.schema.get('option', 'continue', step=step, index=index):
|
|
3440
3419
|
self._error = True
|
|
3441
3420
|
return
|
|
@@ -3467,4 +3446,3 @@ class Chip:
|
|
|
3467
3446
|
|
|
3468
3447
|
# Reinitialize logger on restore
|
|
3469
3448
|
self._init_logger()
|
|
3470
|
-
self.schema._init_logger(self.logger)
|