dv-flow-mgr 0.0.1.12664275031a1__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.
- dv_flow_mgr/__init__.py +6 -0
- dv_flow_mgr/__main__.py +21 -0
- dv_flow_mgr/cmds/cmd_run.py +28 -0
- dv_flow_mgr/fileset.py +31 -0
- dv_flow_mgr/flow.py +59 -0
- dv_flow_mgr/fragment_def.py +46 -0
- dv_flow_mgr/package.py +79 -0
- dv_flow_mgr/package_def.py +97 -0
- dv_flow_mgr/parameters.py +27 -0
- dv_flow_mgr/session.py +247 -0
- dv_flow_mgr/share/flow.json +172 -0
- dv_flow_mgr/task.py +225 -0
- dv_flow_mgr/task_data.py +77 -0
- dv_flow_mgr/task_def.py +45 -0
- dv_flow_mgr/task_memento.py +34 -0
- dv_flow_mgr/tasklib/hdl/sim/mti_pkg.py +11 -0
- dv_flow_mgr/tasklib/hdl/sim/mti_task_sim_image.py +69 -0
- dv_flow_mgr/tasklib/hdl/sim/mti_task_sim_run.py +47 -0
- dv_flow_mgr/tasklib/hdl/sim/pkg_hdl_sim.py +8 -0
- dv_flow_mgr/tasklib/hdl/sim/task_sim_image.py +16 -0
- dv_flow_mgr/tasklib/hdl/sim/vl_task_sim_image.py +72 -0
- dv_flow_mgr/tasklib/hdl/sim/vlt_pkg.py +14 -0
- dv_flow_mgr/tasklib/hdl/sim/vlt_task_sim_image.py +50 -0
- dv_flow_mgr/tasklib/hdl/sim/vlt_task_sim_run.py +45 -0
- dv_flow_mgr/tasklib/std/fileset.py +5 -0
- dv_flow_mgr/tasklib/std/pkg_std.py +15 -0
- dv_flow_mgr/tasklib/std/std.dfs +7 -0
- dv_flow_mgr/tasklib/std/task_fileset.py +89 -0
- dv_flow_mgr/tasklib/std/task_null.py +26 -0
- dv_flow_mgr-0.0.1.12664275031a1.dist-info/LICENSE +201 -0
- dv_flow_mgr-0.0.1.12664275031a1.dist-info/METADATA +211 -0
- dv_flow_mgr-0.0.1.12664275031a1.dist-info/RECORD +35 -0
- dv_flow_mgr-0.0.1.12664275031a1.dist-info/WHEEL +5 -0
- dv_flow_mgr-0.0.1.12664275031a1.dist-info/entry_points.txt +2 -0
- dv_flow_mgr-0.0.1.12664275031a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
|
+
"$id": "https://fvutils.github.io/dv-flow-mgr/flow.json",
|
4
|
+
"title": "Flow-specification schema",
|
5
|
+
"description": "Flow-specification schema",
|
6
|
+
"type": "object",
|
7
|
+
"properties": {
|
8
|
+
"package": {
|
9
|
+
"$ref": "#/defs/package-def"
|
10
|
+
},
|
11
|
+
"fragment": {
|
12
|
+
"$ref": "#/defs/fragment-def"
|
13
|
+
},
|
14
|
+
"oneOf": [
|
15
|
+
{"required": ["package"]},
|
16
|
+
{"required": ["fragment"]}
|
17
|
+
]
|
18
|
+
},
|
19
|
+
"defs": {
|
20
|
+
|
21
|
+
"package-def": {
|
22
|
+
"title": "Package Definition",
|
23
|
+
"$$target": "#/defs/package-def",
|
24
|
+
"type": "object",
|
25
|
+
"properties": {
|
26
|
+
"name": {
|
27
|
+
"type": "string"
|
28
|
+
},
|
29
|
+
"imports": {
|
30
|
+
"type": "array",
|
31
|
+
"items": {
|
32
|
+
"$ref": "#/defs/import-def"
|
33
|
+
}
|
34
|
+
},
|
35
|
+
"with": {
|
36
|
+
"type": "array",
|
37
|
+
"items": {
|
38
|
+
"$ref": "#/defs/param"
|
39
|
+
}
|
40
|
+
},
|
41
|
+
"tasks": {
|
42
|
+
"type": "array",
|
43
|
+
"items": {
|
44
|
+
"$ref": "#/defs/task-def"
|
45
|
+
}
|
46
|
+
},
|
47
|
+
"fragments": {
|
48
|
+
"type": "array",
|
49
|
+
"items": {
|
50
|
+
"type": "string"
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
},
|
55
|
+
|
56
|
+
"import-def": {
|
57
|
+
"title": "Import Definition",
|
58
|
+
"$$target": "#/defs/import-def",
|
59
|
+
"type": "object",
|
60
|
+
"properties": {
|
61
|
+
"name": {
|
62
|
+
"type": "string"
|
63
|
+
},
|
64
|
+
"as": {
|
65
|
+
"type": "string"
|
66
|
+
},
|
67
|
+
"with": {
|
68
|
+
"type": "array",
|
69
|
+
"items": {
|
70
|
+
"$ref": "#/defs/param"
|
71
|
+
}
|
72
|
+
},
|
73
|
+
"from": {
|
74
|
+
"type": "string"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
},
|
78
|
+
|
79
|
+
"fragment-def": {
|
80
|
+
"title": "Fragment Definition",
|
81
|
+
"$$target": "#/defs/fragment-def",
|
82
|
+
"type": "object",
|
83
|
+
"properties": {
|
84
|
+
"imports": {
|
85
|
+
"type": "array",
|
86
|
+
"items": {
|
87
|
+
"type": "string"
|
88
|
+
}
|
89
|
+
},
|
90
|
+
"tasks": {
|
91
|
+
"type": "array",
|
92
|
+
"items": {
|
93
|
+
"$ref": "#/defs/task-def"
|
94
|
+
}
|
95
|
+
},
|
96
|
+
"fragments": {
|
97
|
+
"type": "array",
|
98
|
+
"items": {
|
99
|
+
"type": "string"
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
},
|
104
|
+
"param": {
|
105
|
+
"title": "Parameter Definition",
|
106
|
+
"$$target": "#/defs/param",
|
107
|
+
"type": "object",
|
108
|
+
"properties": {
|
109
|
+
"name": {
|
110
|
+
"type": "string"
|
111
|
+
},
|
112
|
+
"type": {
|
113
|
+
"type": "string"
|
114
|
+
},
|
115
|
+
"value": {
|
116
|
+
"type": "string"
|
117
|
+
}
|
118
|
+
}
|
119
|
+
},
|
120
|
+
"task-dep": {
|
121
|
+
"title": "Task dependency specification",
|
122
|
+
"$$target": "#/defs/task-dep",
|
123
|
+
"type": "object",
|
124
|
+
"properties": {
|
125
|
+
"name": {
|
126
|
+
"type": "string"
|
127
|
+
},
|
128
|
+
"with": {
|
129
|
+
"type": "array",
|
130
|
+
"items": {
|
131
|
+
"$ref": "#/defs/param"
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
},
|
136
|
+
"task-def": {
|
137
|
+
"title": "Task Definition",
|
138
|
+
"$$target": "#/defs/task-def",
|
139
|
+
"type": "object",
|
140
|
+
"properties": {
|
141
|
+
"name": {
|
142
|
+
"type": "string"
|
143
|
+
},
|
144
|
+
"type": {
|
145
|
+
"type": "string"
|
146
|
+
},
|
147
|
+
"with": {
|
148
|
+
"type": "array",
|
149
|
+
"items": {
|
150
|
+
"$ref": "#/defs/param"
|
151
|
+
}
|
152
|
+
},
|
153
|
+
"depends": {
|
154
|
+
"oneOf": [
|
155
|
+
{
|
156
|
+
"type": "array",
|
157
|
+
"items": {
|
158
|
+
"$ref": "#/defs/task-dep"
|
159
|
+
}
|
160
|
+
}, {
|
161
|
+
"type": "array",
|
162
|
+
"items": {
|
163
|
+
"type": "string"
|
164
|
+
}
|
165
|
+
}
|
166
|
+
]
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
dv_flow_mgr/task.py
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import os
|
23
|
+
import json
|
24
|
+
import asyncio
|
25
|
+
import dataclasses as dc
|
26
|
+
from pydantic import BaseModel
|
27
|
+
from typing import Any, Dict, List, Tuple
|
28
|
+
from .task_data import TaskData
|
29
|
+
from .task_memento import TaskMemento
|
30
|
+
|
31
|
+
@dc.dataclass
|
32
|
+
class TaskSpec(object):
|
33
|
+
name : str
|
34
|
+
|
35
|
+
class TaskParams(BaseModel):
|
36
|
+
pass
|
37
|
+
|
38
|
+
@dc.dataclass
|
39
|
+
class TaskCtor(object):
|
40
|
+
def mkTaskParams(self) -> TaskParams:
|
41
|
+
raise NotImplementedError()
|
42
|
+
|
43
|
+
def setTaskParams(self, params : TaskParams, pvals : Dict[str,Any]):
|
44
|
+
for p in pvals.keys():
|
45
|
+
if not hasattr(params, p):
|
46
|
+
raise Exception("Unsupported parameter: " + p)
|
47
|
+
else:
|
48
|
+
setattr(params, p, pvals[p])
|
49
|
+
|
50
|
+
def mkTask(self, name : str, task_id : int, session : 'Session', params : TaskParams, depends : List['Task']) -> 'Task':
|
51
|
+
raise NotImplementedError()
|
52
|
+
|
53
|
+
@dc.dataclass
|
54
|
+
class TaskCtorT(TaskCtor):
|
55
|
+
TaskParamsT : TaskParams
|
56
|
+
TaskT : 'Task'
|
57
|
+
|
58
|
+
def mkTaskParams(self) -> TaskParams:
|
59
|
+
return self.TaskParamsT()
|
60
|
+
|
61
|
+
def mkTask(self, name : str, task_id : int, session : 'Session', params : TaskParams, depends : List['Task']) -> 'Task':
|
62
|
+
task = self.TaskT(
|
63
|
+
name=name,
|
64
|
+
task_id=task_id,
|
65
|
+
session=session,
|
66
|
+
params=params,
|
67
|
+
depends=depends)
|
68
|
+
task.depends.extend(depends)
|
69
|
+
return task
|
70
|
+
|
71
|
+
@dc.dataclass
|
72
|
+
class TaskParamCtor(object):
|
73
|
+
base : TaskCtor
|
74
|
+
params : Dict[str,Any]
|
75
|
+
basedir : str
|
76
|
+
depend_refs : List['TaskSpec']
|
77
|
+
|
78
|
+
def mkTaskParams(self) -> TaskParams:
|
79
|
+
params = self.base.mkTaskParams()
|
80
|
+
self.base.setTaskParams(params, self.params)
|
81
|
+
return params
|
82
|
+
|
83
|
+
def setTaskParams(self, params : Dict, pvals : Dict[str,Any]):
|
84
|
+
pass
|
85
|
+
|
86
|
+
def mkTask(self, name : str, task_id : int, session : 'Session', params : Dict, depends : List['Task']) -> 'Task':
|
87
|
+
task = self.base.mkTask(
|
88
|
+
name=name,
|
89
|
+
task_id=task_id,
|
90
|
+
session=session,
|
91
|
+
params=params,
|
92
|
+
depends=depends)
|
93
|
+
task.basedir = self.basedir
|
94
|
+
task.depend_refs.extend(self.depend_refs)
|
95
|
+
return task
|
96
|
+
|
97
|
+
@dc.dataclass
|
98
|
+
class PackageTaskCtor(TaskCtor):
|
99
|
+
name : str
|
100
|
+
pkg : 'Package'
|
101
|
+
|
102
|
+
def mkTaskParams(self, params : Dict) -> Dict:
|
103
|
+
return self.pkg.mkTaskParams(self.name, params)
|
104
|
+
def mkTask(self, name : str, task_id : int, session : 'Session', params : Dict, depends : List['Task']) -> 'Task':
|
105
|
+
return self.pkg.mkTask(self.name, task_id, session, params, depends)
|
106
|
+
|
107
|
+
@dc.dataclass
|
108
|
+
class Task(object):
|
109
|
+
"""Executable view of a task"""
|
110
|
+
name : str
|
111
|
+
task_id : int
|
112
|
+
session : 'Session'
|
113
|
+
params : TaskParams
|
114
|
+
basedir : str
|
115
|
+
srcdir : str = None
|
116
|
+
memento : TaskMemento = None
|
117
|
+
depend_refs : List['TaskSpec'] = dc.field(default_factory=list)
|
118
|
+
depends : List[int] = dc.field(default_factory=list)
|
119
|
+
running : bool = False
|
120
|
+
output_set : bool = False
|
121
|
+
output : Any = None
|
122
|
+
output_ev : Any = asyncio.Event()
|
123
|
+
|
124
|
+
# Implementation data below
|
125
|
+
basedir : str = dc.field(default=None)
|
126
|
+
rundir : str = dc.field(default=None)
|
127
|
+
impl : str = None
|
128
|
+
body: Dict[str,Any] = dc.field(default_factory=dict)
|
129
|
+
impl_t : Any = None
|
130
|
+
|
131
|
+
def getMemento(self, T) -> TaskMemento:
|
132
|
+
if os.path.isfile(os.path.join(self.rundir, "memento.json")):
|
133
|
+
with open(os.path.join(self.rundir, "memento.json"), "r") as fp:
|
134
|
+
try:
|
135
|
+
data = json.load(fp)
|
136
|
+
self.memento = T(**data)
|
137
|
+
except Exception as e:
|
138
|
+
print("Failed to load memento %s: %s" % (
|
139
|
+
os.path.join(self.rundir, "memento.json"), str(e)))
|
140
|
+
os.unlink(os.path.join(self.rundir, "memento.json"))
|
141
|
+
return self.memento
|
142
|
+
|
143
|
+
def setMemento(self, memento : TaskMemento):
|
144
|
+
self.memento = memento
|
145
|
+
|
146
|
+
async def do_run(self) -> TaskData:
|
147
|
+
print("do_run: %s - %d depends" % (self.name, len(self.depends)))
|
148
|
+
if len(self.depends) > 0:
|
149
|
+
awaitables = [dep.waitOutput() for dep in self.depends]
|
150
|
+
deps_o = await asyncio.gather(*awaitables)
|
151
|
+
|
152
|
+
print("deps_o: %s" % str(deps_o))
|
153
|
+
|
154
|
+
# Merge the output of the dependencies into a single input data
|
155
|
+
# if len(self.depends) > 1:
|
156
|
+
# raise Exception("TODO: handle >1 inputs")
|
157
|
+
|
158
|
+
input = self.depends[0].output.copy()
|
159
|
+
else:
|
160
|
+
input = TaskData()
|
161
|
+
|
162
|
+
if not os.path.isdir(self.rundir):
|
163
|
+
os.makedirs(self.rundir)
|
164
|
+
|
165
|
+
result = await self.run(input)
|
166
|
+
|
167
|
+
if not self.output_set:
|
168
|
+
if result is None:
|
169
|
+
result = TaskData()
|
170
|
+
|
171
|
+
# We perform an auto-merge algorithm if the task
|
172
|
+
# doesn't take control
|
173
|
+
# for dep_o in deps_o:
|
174
|
+
# result.deps.append(dep_o.clone())
|
175
|
+
|
176
|
+
self.setOutput(result)
|
177
|
+
else:
|
178
|
+
# The task has taken control of the output
|
179
|
+
result = self.getOutput()
|
180
|
+
|
181
|
+
# Write-back the memento, if specified
|
182
|
+
if self.memento is not None:
|
183
|
+
with open(os.path.join(self.rundir, "memento.json"), "w") as fp:
|
184
|
+
fp.write(self.memento.model_dump_json(indent=2))
|
185
|
+
|
186
|
+
self.running = False
|
187
|
+
|
188
|
+
# Combine data from the deps to produce a result
|
189
|
+
return result
|
190
|
+
|
191
|
+
async def run(self, input : TaskData) -> TaskData:
|
192
|
+
raise NotImplementedError("TaskImpl.run() not implemented")
|
193
|
+
|
194
|
+
def setOutput(self, output : TaskData):
|
195
|
+
self.output_set = True
|
196
|
+
output.task_id = self.task_id
|
197
|
+
self.output = output
|
198
|
+
self.output_ev.set()
|
199
|
+
|
200
|
+
async def waitOutput(self) -> TaskData:
|
201
|
+
if not self.output_set:
|
202
|
+
if self.running:
|
203
|
+
# Task is already running
|
204
|
+
print("wait")
|
205
|
+
await self.output_ev.wait()
|
206
|
+
else:
|
207
|
+
self.running = True
|
208
|
+
print("start task")
|
209
|
+
await self.do_run()
|
210
|
+
return self.output
|
211
|
+
|
212
|
+
def getOutput(self) -> TaskData:
|
213
|
+
return self.output
|
214
|
+
|
215
|
+
def getField(self, name : str) -> Any:
|
216
|
+
if name in self.__dict__.keys():
|
217
|
+
return self.__dict__[name]
|
218
|
+
elif name in self.__pydantic_extra__.keys():
|
219
|
+
return self.__pydantic_extra__[name]
|
220
|
+
else:
|
221
|
+
raise Exception("No such field %s" % name)
|
222
|
+
|
223
|
+
|
224
|
+
|
225
|
+
|
dv_flow_mgr/task_data.py
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_data.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import pydantic.dataclasses as dc
|
23
|
+
from pydantic import BaseModel
|
24
|
+
from typing import Any, Dict, Set, List, Tuple
|
25
|
+
from .fileset import FileSet
|
26
|
+
|
27
|
+
class TaskData(BaseModel):
|
28
|
+
task_id : int = -1
|
29
|
+
params : Dict[str,Any] = dc.Field(default_factory=dict)
|
30
|
+
deps : List['TaskData'] = dc.Field(default_factory=list)
|
31
|
+
changed : bool = False
|
32
|
+
|
33
|
+
def hasParam(self, name: str) -> bool:
|
34
|
+
return name in self.params
|
35
|
+
|
36
|
+
def getParam(self, name: str) -> Any:
|
37
|
+
return self.params[name]
|
38
|
+
|
39
|
+
def setParam(self, name: str, value: Any):
|
40
|
+
self.params[name] = value
|
41
|
+
|
42
|
+
def addFileSet(self, fs : FileSet):
|
43
|
+
if "filesets" not in self.params:
|
44
|
+
self.params["filesets"] = []
|
45
|
+
self.params["filesets"].append(fs)
|
46
|
+
|
47
|
+
def getFileSets(self, type : (str|Set[str])=None) -> List[FileSet]:
|
48
|
+
ret = []
|
49
|
+
|
50
|
+
if "filesets" in self.params:
|
51
|
+
for fs in self.params["filesets"]:
|
52
|
+
if type is None or fs.type in type:
|
53
|
+
ret.append(fs)
|
54
|
+
|
55
|
+
return ret
|
56
|
+
|
57
|
+
def copy(self) -> 'TaskData':
|
58
|
+
ret = TaskData()
|
59
|
+
ret.task_id = self.task_id
|
60
|
+
ret.params = self.params.copy()
|
61
|
+
for d in self.deps:
|
62
|
+
ret.deps.append(d.clone())
|
63
|
+
ret.changed = self.changed
|
64
|
+
return ret
|
65
|
+
|
66
|
+
def merge(self, other):
|
67
|
+
for k,v in other.params.items():
|
68
|
+
if k not in self.params:
|
69
|
+
if hasattr(v, "copy"):
|
70
|
+
self.params[k] = v.copy()
|
71
|
+
else:
|
72
|
+
self.params[k] = v
|
73
|
+
elif hasattr(self.params[k], "merge"):
|
74
|
+
self.params[k].merge(v)
|
75
|
+
elif self.params[k] != v:
|
76
|
+
raise Exception("Parameter %s has conflicting values" % k)
|
77
|
+
|
dv_flow_mgr/task_def.py
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_def.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import pydantic.dataclasses as dc
|
23
|
+
from pydantic import BaseModel
|
24
|
+
from typing import Any, Dict, List, Tuple
|
25
|
+
from .task import Task
|
26
|
+
|
27
|
+
@dc.dataclass
|
28
|
+
class TaskSpec(object):
|
29
|
+
name : str
|
30
|
+
|
31
|
+
|
32
|
+
class TaskDef(BaseModel):
|
33
|
+
"""Holds definition information (ie the YAML view) for a task"""
|
34
|
+
name : str
|
35
|
+
type : (str|TaskSpec) = dc.Field(default_factory=list)
|
36
|
+
depends : List[(str|TaskSpec)] = dc.Field(default_factory=list)
|
37
|
+
params: Dict[str,Any] = dc.Field(default_factory=dict, alias="with")
|
38
|
+
|
39
|
+
def copy(self) -> 'TaskDef':
|
40
|
+
ret = TaskDef(
|
41
|
+
name=self.name,
|
42
|
+
type=self.type,
|
43
|
+
depends=self.depends.copy())
|
44
|
+
return ret
|
45
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_memento.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import pydantic.dataclasses as dc
|
23
|
+
from pydantic import BaseModel
|
24
|
+
from typing import Any, Dict, List
|
25
|
+
|
26
|
+
class TaskMemento(BaseModel):
|
27
|
+
# dep_ids : List[int] = dc.Field(default_factory=list)
|
28
|
+
# params : Dict[str,Any] = dc.Field(default_factory=dict)
|
29
|
+
|
30
|
+
pass
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
from .pkg_hdl_sim import PackageHdlSim
|
3
|
+
from .mti_task_sim_image import TaskMtiSimImageCtor
|
4
|
+
from .mti_task_sim_run import TaskMtiSimRunCtor
|
5
|
+
|
6
|
+
@dc.dataclass
|
7
|
+
class MtiPackage(PackageHdlSim):
|
8
|
+
def __post_init__(self):
|
9
|
+
self.tasks["SimImage"] = TaskMtiSimImageCtor()
|
10
|
+
self.tasks["SimRun"] = TaskMtiSimRunCtor()
|
11
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import os
|
2
|
+
import fnmatch
|
3
|
+
import dataclasses as dc
|
4
|
+
from ....fileset import FileSet
|
5
|
+
from ....package import TaskCtor
|
6
|
+
from ....task import Task, TaskParams, TaskCtorT
|
7
|
+
from ....task_data import TaskData
|
8
|
+
from ....task_memento import TaskMemento
|
9
|
+
from .vl_task_sim_image import VlTaskSimImage, VlTaskSimImageParams, VlTaskSimImageMemento
|
10
|
+
from typing import List, Tuple
|
11
|
+
|
12
|
+
from svdep import FileCollection, TaskCheckUpToDate, TaskBuildFileCollection
|
13
|
+
|
14
|
+
@dc.dataclass
|
15
|
+
class TaskMtiSimImage(VlTaskSimImage):
|
16
|
+
|
17
|
+
def getRefTime(self):
|
18
|
+
if os.path.isdir(os.path.join(self.rundir, 'work.d')):
|
19
|
+
return os.path.getmtime(os.path.join(self.rundir, 'work.d'))
|
20
|
+
else:
|
21
|
+
raise Exception("work.d not found")
|
22
|
+
|
23
|
+
async def build(self, files : List[str], incdirs : List[str]):
|
24
|
+
if not os.path.isdir(os.path.join(self.rundir, 'work')):
|
25
|
+
cmd = ['vlib', 'work']
|
26
|
+
proc = await self.session.create_subprocess(*cmd,
|
27
|
+
cwd=self.rundir)
|
28
|
+
await proc.wait()
|
29
|
+
if proc.returncode != 0:
|
30
|
+
raise Exception("Questa vlib failed")
|
31
|
+
|
32
|
+
cmd = ['vlog', '-sv']
|
33
|
+
|
34
|
+
for incdir in incdirs:
|
35
|
+
cmd.append('+incdir+%s' % incdir)
|
36
|
+
|
37
|
+
cmd.extend(files)
|
38
|
+
|
39
|
+
proc = await self.session.create_subprocess(*cmd,
|
40
|
+
cwd=self.rundir)
|
41
|
+
await proc.wait()
|
42
|
+
if proc.returncode != 0:
|
43
|
+
raise Exception("Questa compile failed")
|
44
|
+
|
45
|
+
cmd = ['vopt', '-o', 'simv_opt']
|
46
|
+
|
47
|
+
for top in self.params.top:
|
48
|
+
cmd.append(top)
|
49
|
+
|
50
|
+
proc = await self.session.create_subprocess(*cmd,
|
51
|
+
cwd=self.rundir)
|
52
|
+
|
53
|
+
await proc.wait()
|
54
|
+
|
55
|
+
with open(os.path.join(self.rundir, 'work.d'), "w") as fp:
|
56
|
+
pass
|
57
|
+
|
58
|
+
if proc.returncode != 0:
|
59
|
+
raise Exception("Questa opt failed")
|
60
|
+
|
61
|
+
class TaskMtiSimImageParams(VlTaskSimImageParams):
|
62
|
+
pass
|
63
|
+
|
64
|
+
class TaskMtiSimImageMemento(VlTaskSimImageMemento):
|
65
|
+
pass
|
66
|
+
|
67
|
+
class TaskMtiSimImageCtor(TaskCtorT):
|
68
|
+
def __init__(self):
|
69
|
+
super().__init__(TaskMtiSimImageParams, TaskMtiSimImage)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import os
|
2
|
+
import fnmatch
|
3
|
+
import pydantic.dataclasses as dc
|
4
|
+
from ....fileset import FileSet
|
5
|
+
from ....package import TaskCtor
|
6
|
+
from ....task import Task, TaskParams, TaskCtorT
|
7
|
+
from ....task_data import TaskData
|
8
|
+
from ....task_memento import TaskMemento
|
9
|
+
from typing import List, Tuple
|
10
|
+
|
11
|
+
class TaskMtiSimRun(Task):
|
12
|
+
|
13
|
+
async def run(self, input : TaskData) -> TaskData:
|
14
|
+
vl_fileset = input.getFileSets("verilatorBinary")
|
15
|
+
|
16
|
+
build_dir = vl_fileset[0].basedir
|
17
|
+
|
18
|
+
cmd = [
|
19
|
+
'vsim', '-batch', '-do', 'run -all; quit -f',
|
20
|
+
'-work', os.path.join(build_dir, 'work'),
|
21
|
+
'simv_opt'
|
22
|
+
]
|
23
|
+
|
24
|
+
fp = open(os.path.join(self.rundir, 'sim.log'), "w")
|
25
|
+
proc = await self.session.create_subprocess(*cmd,
|
26
|
+
cwd=self.rundir,
|
27
|
+
stdout=fp)
|
28
|
+
|
29
|
+
await proc.wait()
|
30
|
+
|
31
|
+
fp.close()
|
32
|
+
|
33
|
+
output = TaskData()
|
34
|
+
output.addFileSet(FileSet(src=self.name, type="simRunDir", basedir=self.rundir))
|
35
|
+
|
36
|
+
return output
|
37
|
+
|
38
|
+
class TaskMtiSimRunParams(TaskParams):
|
39
|
+
pass
|
40
|
+
|
41
|
+
class TaskMtiSimRunMemento(TaskMemento):
|
42
|
+
pass
|
43
|
+
|
44
|
+
class TaskMtiSimRunCtor(TaskCtorT):
|
45
|
+
def __init__(self):
|
46
|
+
super().__init__(TaskMtiSimRunParams, TaskMtiSimRun)
|
47
|
+
|