zuspec-dataclasses 0.0.1.17516204125rc0__py3-none-any.whl → 0.0.1.18247373596rc0__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.
- zuspec/dataclasses/__init__.py +23 -3
- zuspec/dataclasses/__version__.py +16 -1
- zuspec/dataclasses/action.py +15 -0
- zuspec/dataclasses/addr_reg.py +32 -3
- zuspec/dataclasses/annotation.py +15 -0
- zuspec/dataclasses/api/__init__.py +16 -0
- zuspec/dataclasses/api/type_processor.py +26 -0
- zuspec/dataclasses/api/visitor.py +296 -16
- zuspec/dataclasses/bit.py +17 -53
- zuspec/dataclasses/bundle.py +17 -0
- zuspec/dataclasses/component.py +44 -2
- zuspec/dataclasses/decorators.py +162 -60
- zuspec/dataclasses/dependency.py +15 -1
- zuspec/dataclasses/ports.py +0 -5
- zuspec/dataclasses/std/__init__.py +18 -0
- zuspec/dataclasses/std/clock_reset.py +35 -0
- zuspec/dataclasses/std/timebase.py +45 -0
- zuspec/dataclasses/struct.py +9 -2
- {zuspec_dataclasses-0.0.1.17516204125rc0.dist-info → zuspec_dataclasses-0.0.1.18247373596rc0.dist-info}/METADATA +1 -1
- zuspec_dataclasses-0.0.1.18247373596rc0.dist-info/RECORD +29 -0
- zuspec/dataclasses/clock.py +0 -3
- zuspec/dataclasses/reset.py +0 -3
- zuspec/dataclasses/timebase.py +0 -27
- zuspec_dataclasses-0.0.1.17516204125rc0.dist-info/RECORD +0 -28
- {zuspec_dataclasses-0.0.1.17516204125rc0.dist-info → zuspec_dataclasses-0.0.1.18247373596rc0.dist-info}/WHEEL +0 -0
- {zuspec_dataclasses-0.0.1.17516204125rc0.dist-info → zuspec_dataclasses-0.0.1.18247373596rc0.dist-info}/licenses/LICENSE +0 -0
- {zuspec_dataclasses-0.0.1.17516204125rc0.dist-info → zuspec_dataclasses-0.0.1.18247373596rc0.dist-info}/top_level.txt +0 -0
zuspec/dataclasses/__init__.py
CHANGED
@@ -1,7 +1,22 @@
|
|
1
1
|
|
2
2
|
|
3
|
+
#****************************************************************************
|
4
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may 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
|
+
#****************************************************************************
|
3
18
|
# from .activity_stmts import *
|
4
|
-
from .decorators import dataclass, field, export, process, input, output, sync, const, port, export, bind
|
19
|
+
from .decorators import dataclass, field, export, extern, process, input, output, sync, const, port, export, bind
|
5
20
|
from .tlm import *
|
6
21
|
# from .claims_refs import *
|
7
22
|
# from .shared_stmts import *
|
@@ -9,9 +24,14 @@ from .tlm import *
|
|
9
24
|
# from .core_lib import *
|
10
25
|
# from vsc_dataclasses.expr import *
|
11
26
|
|
12
|
-
from .
|
27
|
+
from . import std
|
28
|
+
|
29
|
+
from .bit import Bit
|
30
|
+
from .action import Action
|
31
|
+
from .std.clock_reset import ClockReset
|
13
32
|
from .component import Component
|
14
|
-
from .
|
33
|
+
from .exec import ExecSync, Exec
|
34
|
+
from .struct import Struct, ZuspecTypeBase
|
15
35
|
from .ports import Input, Output, Port
|
16
36
|
|
17
37
|
from asyncio import Event
|
@@ -1,4 +1,19 @@
|
|
1
1
|
|
2
|
+
#****************************************************************************
|
3
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#****************************************************************************
|
2
17
|
BASE="0.0.1"
|
3
|
-
SUFFIX=".
|
18
|
+
SUFFIX=".18247373596rc0"
|
4
19
|
VERSION="%s%s" % (BASE, SUFFIX)
|
zuspec/dataclasses/action.py
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
1
16
|
from typing import Self, Type, TypeVar
|
2
17
|
from .decorators import dataclass, field
|
3
18
|
from .component import Component
|
zuspec/dataclasses/addr_reg.py
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
1
16
|
import abc
|
2
17
|
import zuspec.dataclasses as zdc
|
3
|
-
from typing import Annotated, TypeVar, Type, Union
|
4
|
-
from .bit import BitVal
|
5
|
-
from .decorators import dataclass, constraint
|
18
|
+
from typing import Annotated, Dict, TypeVar, Type, Union
|
6
19
|
from .struct import StructPacked
|
7
20
|
|
8
21
|
class AddrHandle(): pass
|
@@ -58,6 +71,8 @@ class Reg[RegT](object):
|
|
58
71
|
"""Writes the value of the register"""
|
59
72
|
pass
|
60
73
|
|
74
|
+
def write_fields(self, fields : Dict[object,int]): pass
|
75
|
+
|
61
76
|
class RegGroup(object):
|
62
77
|
@abc.abstractmethod
|
63
78
|
def get_handle(self) -> AddrHandle:
|
@@ -70,3 +85,17 @@ class RegGroup(object):
|
|
70
85
|
pass
|
71
86
|
|
72
87
|
|
88
|
+
class At(object):
|
89
|
+
a : zdc.Bit[15] = zdc.field()
|
90
|
+
b : zdc.Bit[15] = zdc.field()
|
91
|
+
|
92
|
+
# def __int__(self) -> int:
|
93
|
+
# pass
|
94
|
+
|
95
|
+
# r : Reg[At] = 5
|
96
|
+
# r.read() == 20
|
97
|
+
# r.write()
|
98
|
+
# r.write_fields({At.a : 5})
|
99
|
+
# def reg(offset=)
|
100
|
+
|
101
|
+
# def reg_array(offset=0, offset_of=lambda i: )
|
zuspec/dataclasses/annotation.py
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
1
16
|
import dataclasses as dc
|
2
17
|
from typing import Callable, ClassVar
|
3
18
|
|
@@ -1,2 +1,18 @@
|
|
1
1
|
|
2
|
+
#****************************************************************************
|
3
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#****************************************************************************
|
17
|
+
from .type_processor import TypeProcessor
|
2
18
|
from .visitor import Visitor
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
16
|
+
import abc
|
17
|
+
|
18
|
+
class TypeProcessor(object):
|
19
|
+
|
20
|
+
@abc.abstractmethod
|
21
|
+
def new(self, c, *args, **kwargs):
|
22
|
+
pass
|
23
|
+
|
24
|
+
@abc.abstractmethod
|
25
|
+
def init(self, obj, *args, **kwargs):
|
26
|
+
pass
|
@@ -1,14 +1,61 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
1
16
|
import dataclasses as dc
|
2
|
-
|
17
|
+
import logging
|
18
|
+
from dataclasses import Field, MISSING
|
19
|
+
from typing import Callable, ClassVar, Dict, Type, List, Tuple
|
3
20
|
from ..annotation import Annotation
|
21
|
+
from ..bit import Bit
|
4
22
|
from ..component import Component
|
23
|
+
from ..exec import Exec, ExecKind, ExecSync
|
5
24
|
from ..ports import Input, Output
|
6
|
-
from ..struct import Struct
|
25
|
+
from ..struct import Extern, Struct
|
26
|
+
import inspect
|
27
|
+
import ast
|
28
|
+
import textwrap
|
29
|
+
|
30
|
+
class _BindPathMock:
|
31
|
+
def __init__(self, typ, path=None):
|
32
|
+
self._typ = typ
|
33
|
+
self._path = path or []
|
34
|
+
|
35
|
+
def __getattribute__(self, name):
|
36
|
+
if name in ("_typ", "_path", "__class__"):
|
37
|
+
return object.__getattribute__(self, name)
|
38
|
+
# Validate field exists
|
39
|
+
fields = {f.name for f in dc.fields(self._typ)}
|
40
|
+
if name not in fields:
|
41
|
+
raise AttributeError(f"Invalid field '{name}' in path {'.'.join(self._path + [name])}")
|
42
|
+
# Get field type
|
43
|
+
field_type = next(f.type for f in dc.fields(self._typ) if f.name == name)
|
44
|
+
# Return new mock for nested access
|
45
|
+
return _BindPathMock(field_type, self._path + [name])
|
46
|
+
|
47
|
+
def __call__(self):
|
48
|
+
# For supporting callables if needed
|
49
|
+
return self
|
50
|
+
|
51
|
+
def __repr__(self):
|
52
|
+
return f"_BindPathMock({self._typ}, {self._path})"
|
7
53
|
|
8
54
|
@dc.dataclass
|
9
55
|
class Visitor(object):
|
10
56
|
_type_m : Dict[Type,Callable] = dc.field(default_factory=dict)
|
11
57
|
_field_factory_m : Dict[Type,Callable] = dc.field(default_factory=dict)
|
58
|
+
_log : ClassVar = logging.getLogger("Visitor")
|
12
59
|
|
13
60
|
def __post_init__(self):
|
14
61
|
self._type_m = {
|
@@ -20,41 +67,274 @@ class Visitor(object):
|
|
20
67
|
}
|
21
68
|
|
22
69
|
def visit(self, t):
|
70
|
+
# Accept both class and instance
|
71
|
+
t_cls = t if isinstance(t, type) else type(t)
|
23
72
|
found = False
|
24
73
|
for base_t,method in self._type_m.items():
|
25
|
-
if issubclass(
|
74
|
+
if issubclass(t_cls, base_t):
|
26
75
|
method(t)
|
27
76
|
found = True
|
28
77
|
break
|
29
78
|
if not found:
|
30
|
-
raise Exception("Unsupported class %s" % str(
|
79
|
+
raise Exception("Unsupported class %s" % str(t))
|
31
80
|
|
32
81
|
def visitComponentType(self, t):
|
33
|
-
|
82
|
+
# Always work with the class, not the instance
|
83
|
+
t_cls = t if isinstance(t, type) else type(t)
|
84
|
+
self.visitStructType(t_cls)
|
34
85
|
pass
|
35
86
|
|
36
|
-
def
|
87
|
+
def _elabBindPath(self, path_lambda, root_type):
|
88
|
+
"""
|
89
|
+
Processes a lambda expression returning a single property path.
|
90
|
+
Returns: (field_obj, path_tuple)
|
91
|
+
"""
|
92
|
+
root_mock = _BindPathMock(root_type, ["s"])
|
93
|
+
result_mock = path_lambda(root_mock)
|
94
|
+
path = getattr(result_mock, "_path", None)
|
95
|
+
if path is None:
|
96
|
+
raise ValueError("Lambda must return a _BindPathMock instance")
|
97
|
+
typ = root_type
|
98
|
+
for name in path[1:]: # skip 's'
|
99
|
+
field = next(f for f in dc.fields(typ) if f.name == name)
|
100
|
+
typ = field.type
|
101
|
+
return (field, tuple(path))
|
102
|
+
|
103
|
+
def _elabBinds(self, bind_lambda, root_type):
|
104
|
+
# Instantiate mock for root
|
105
|
+
root_mock = _BindPathMock(root_type, ["s"])
|
106
|
+
# Evaluate lambda to get mapping
|
107
|
+
mapping = bind_lambda(root_mock)
|
108
|
+
result = {}
|
109
|
+
for k, v in mapping.items():
|
110
|
+
# Extract path from mock objects
|
111
|
+
k_path = getattr(k, "_path", None)
|
112
|
+
v_path = getattr(v, "_path", None)
|
113
|
+
if k_path is None or v_path is None:
|
114
|
+
raise ValueError("Bind keys/values must be _BindPathMock instances")
|
115
|
+
# Get terminal Field for key
|
116
|
+
k_typ = root_type
|
117
|
+
for name in k_path[1:]: # skip 's'
|
118
|
+
field = next(f for f in dc.fields(k_typ) if f.name == name)
|
119
|
+
k_typ = field.type
|
120
|
+
k_field = field
|
121
|
+
# Get terminal Field for value
|
122
|
+
v_typ = root_type
|
123
|
+
for name in v_path[1:]:
|
124
|
+
field = next(f for f in dc.fields(v_typ) if f.name == name)
|
125
|
+
v_typ = field.type
|
126
|
+
v_field = field
|
127
|
+
result[(k_field, tuple(k_path))] = (v_field, tuple(v_path))
|
128
|
+
return result
|
129
|
+
|
130
|
+
def _visitFields(self, t : Struct):
|
131
|
+
print("--> visitFields")
|
37
132
|
for f in dc.fields(t):
|
133
|
+
print("Field: %s" % f.name)
|
38
134
|
self._dispatchField(f)
|
135
|
+
|
136
|
+
def _dispatchField(self, f : dc.Field):
|
137
|
+
if f.default_factory not in (None, dc.MISSING):
|
138
|
+
if issubclass(f.default_factory, Input):
|
139
|
+
self.visitFieldInOut(f, False)
|
140
|
+
elif issubclass(f.default_factory, Output):
|
141
|
+
self.visitFieldInOut(f, True)
|
142
|
+
elif issubclass(f.default_factory, Exec):
|
143
|
+
self.visitExec(f)
|
144
|
+
elif issubclass(f.default_factory, Extern):
|
145
|
+
self.visitFieldExtern(f)
|
146
|
+
else:
|
147
|
+
raise Exception("Unknown factory %s" % f.default_factory)
|
148
|
+
pass
|
149
|
+
elif f.type in (str, int, float):
|
150
|
+
self.visitFieldData(f)
|
151
|
+
elif issubclass(f.type, Component):
|
152
|
+
print("visitFieldClass: Component %s" % f, flush=True)
|
153
|
+
self.visitFieldClass(f)
|
154
|
+
else:
|
155
|
+
print("visitFieldClass: %s" % f, flush=True)
|
156
|
+
self.visitFieldClass(f)
|
157
|
+
|
158
|
+
def _visitExecs(self, t):
|
159
|
+
exec_t = (
|
160
|
+
(ExecSync, self.visitExecSync),
|
161
|
+
(Exec, self.visitExec)
|
162
|
+
)
|
163
|
+
for n in dir(t):
|
164
|
+
o = getattr(t, n)
|
165
|
+
for et, em in exec_t:
|
166
|
+
if isinstance(o, et):
|
167
|
+
em(o)
|
168
|
+
break
|
169
|
+
|
170
|
+
def _visitFunctions(self, t):
|
171
|
+
for e in dir(t):
|
172
|
+
if not e.startswith("__") and callable(getattr(t, e)):
|
173
|
+
print("Function: %s" % e)
|
174
|
+
self.visitFunction(getattr(t, e))
|
175
|
+
|
176
|
+
def visitFunction(self, f):
|
177
|
+
pass
|
178
|
+
|
179
|
+
def _visitDataType(self, t):
|
180
|
+
|
181
|
+
if t == int:
|
182
|
+
self.visitDataTypeInt()
|
183
|
+
elif type(t) is type:
|
184
|
+
zsp_base_t = (
|
185
|
+
(Component, self.visitDataTypeComponent),
|
186
|
+
)
|
187
|
+
|
188
|
+
v = None
|
189
|
+
for tt,vv in zsp_base_t:
|
190
|
+
print("t: %s tt: %s vv: %s" % (t, tt, vv))
|
191
|
+
if issubclass(t, tt):
|
192
|
+
v = vv
|
193
|
+
break
|
194
|
+
|
195
|
+
v(t)
|
196
|
+
else:
|
197
|
+
raise Exception("Unknown type %s" % str(t))
|
198
|
+
pass
|
199
|
+
|
200
|
+
def visitDataTypeComponent(self, t):
|
201
|
+
pass
|
202
|
+
|
203
|
+
def visitDataTypeInt(self):
|
204
|
+
pass
|
205
|
+
|
206
|
+
def visitField(self, f : dc.Field):
|
207
|
+
pass
|
208
|
+
|
209
|
+
def visitFieldClass(self, f : dc.Field):
|
210
|
+
self.visitField(f)
|
211
|
+
|
212
|
+
def visitFieldInOut(self, f : dc.Field, is_out : bool):
|
213
|
+
self.visitField(f)
|
214
|
+
|
215
|
+
def visitFieldData(self, f : dc.Field):
|
216
|
+
self.visitField(f)
|
217
|
+
self._visitDataType(f.type)
|
218
|
+
|
219
|
+
def visitStructType(self, t : Struct):
|
220
|
+
self._visitFields(t)
|
221
|
+
self._visitExecs(t)
|
39
222
|
|
40
223
|
for f in dir(t):
|
41
224
|
o = getattr(t, f)
|
42
|
-
|
43
|
-
|
44
|
-
|
225
|
+
# if callable(o) and hasattr(o, Annotation.NAME):
|
226
|
+
# # Extract source code of the method
|
227
|
+
# try:
|
228
|
+
# src = inspect.getsource(o)
|
229
|
+
# src = textwrap.dedent(src)
|
230
|
+
# tree = ast.parse(src)
|
231
|
+
# for stmt in tree.body[0].body: # tree.body[0] is the FunctionDef
|
232
|
+
# self.visit_statement(stmt)
|
233
|
+
# except Exception as e:
|
234
|
+
# print(f"Could not process method {f}: {e}")
|
235
|
+
# # self.visitExec(f, o)
|
236
|
+
# # print("Found")
|
237
|
+
|
238
|
+
def _findFieldRefs(self, t : Struct, method) -> List[Tuple[bool,dc.Field,Tuple[str]]]:
|
239
|
+
"""
|
240
|
+
Processes the body of a Python method to identify class members
|
241
|
+
referenced inside.
|
242
|
+
Returns: List of [<is_write>,[path]]
|
243
|
+
"""
|
244
|
+
import inspect, ast, textwrap
|
245
|
+
|
246
|
+
src = inspect.getsource(method)
|
247
|
+
src = textwrap.dedent(src)
|
248
|
+
tree = ast.parse(src)
|
249
|
+
refs = []
|
250
|
+
|
251
|
+
# Map field names to Field objects
|
252
|
+
field_map = {f.name: f for f in dc.fields(t)}
|
253
|
+
|
254
|
+
class FieldRefVisitor(ast.NodeVisitor):
|
255
|
+
def __init__(self):
|
256
|
+
self.refs = []
|
257
|
+
|
258
|
+
def visit_Assign(self, node):
|
259
|
+
# Left-hand side: writes
|
260
|
+
for target in node.targets:
|
261
|
+
if isinstance(target, ast.Attribute) and isinstance(target.value, ast.Name) and target.value.id == "self":
|
262
|
+
field = target.attr
|
263
|
+
if field in field_map:
|
264
|
+
self.refs.append((True, field_map[field], ("self", field)))
|
265
|
+
# Right-hand side: reads
|
266
|
+
self.visit(node.value)
|
267
|
+
|
268
|
+
def visit_Attribute(self, node):
|
269
|
+
if isinstance(node.value, ast.Name) and node.value.id == "self":
|
270
|
+
field = node.attr
|
271
|
+
if field in field_map:
|
272
|
+
self.refs.append((False, field_map[field], ("self", field)))
|
273
|
+
self.generic_visit(node)
|
274
|
+
|
275
|
+
visitor = FieldRefVisitor()
|
276
|
+
for stmt in tree.body[0].body:
|
277
|
+
visitor.visit(stmt)
|
278
|
+
|
279
|
+
# Remove duplicate refs (e.g., multiple reads/writes)
|
280
|
+
unique_refs = []
|
281
|
+
seen = set()
|
282
|
+
for ref in visitor.refs:
|
283
|
+
key = (ref[0], ref[1].name, ref[2])
|
284
|
+
if key not in seen:
|
285
|
+
unique_refs.append(ref)
|
286
|
+
seen.add(key)
|
287
|
+
return unique_refs
|
45
288
|
|
46
|
-
def visitExec(self,
|
289
|
+
def visitExec(self, e : Exec):
|
47
290
|
pass
|
48
291
|
|
49
|
-
def
|
50
|
-
|
51
|
-
self._field_factory_m[f.default_factory](f)
|
52
|
-
else:
|
53
|
-
self.visitField(f)
|
292
|
+
def visitExecSync(self, e : ExecSync):
|
293
|
+
self.visitExec(e)
|
54
294
|
|
55
|
-
def
|
295
|
+
def visitFieldExtern(self, f : dc.Field):
|
56
296
|
pass
|
57
297
|
|
298
|
+
def visitOutputField(self, f : dc.Field):
|
299
|
+
self.visitField(f)
|
300
|
+
|
301
|
+
def visitIntField(self, f : dc.Field):
|
302
|
+
self.visitField(f)
|
303
|
+
|
304
|
+
def visitStrField(self, f : dc.Field):
|
305
|
+
self.visitField(f)
|
306
|
+
|
307
|
+
def visit_statement(self, stmt):
|
308
|
+
method = f"visit_{type(stmt).__name__}"
|
309
|
+
visitor = getattr(self, method, self.generic_visit)
|
310
|
+
return visitor(stmt)
|
311
|
+
|
312
|
+
def generic_visit(self, stmt):
|
313
|
+
# Recursively visit child statements if present
|
314
|
+
for field, value in ast.iter_fields(stmt):
|
315
|
+
if isinstance(value, list):
|
316
|
+
for item in value:
|
317
|
+
if isinstance(item, ast.stmt):
|
318
|
+
self.visit_statement(item)
|
319
|
+
elif isinstance(value, ast.stmt):
|
320
|
+
self.visit_statement(value)
|
321
|
+
|
322
|
+
def visit_Assign(self, stmt: ast.Assign):
|
323
|
+
# Example: handle assignment statements
|
324
|
+
# Recursively visit child nodes if needed
|
325
|
+
self.generic_visit(stmt)
|
326
|
+
|
327
|
+
def visit_If(self, stmt: ast.If):
|
328
|
+
# Example: handle if statements
|
329
|
+
for s in stmt.body:
|
330
|
+
self.visit_statement(s)
|
331
|
+
for s in stmt.orelse:
|
332
|
+
self.visit_statement(s)
|
333
|
+
|
334
|
+
def visit_Expr(self, stmt: ast.Expr):
|
335
|
+
# Example: handle expression statements
|
336
|
+
self.generic_visit(stmt)
|
337
|
+
|
58
338
|
def visitInput(self, f : dc.Field):
|
59
339
|
self.visitField(f)
|
60
340
|
pass
|
zuspec/dataclasses/bit.py
CHANGED
@@ -2,6 +2,11 @@ import dataclasses as dc
|
|
2
2
|
from typing import Dict, Generic, TypeVar, Literal, Type
|
3
3
|
|
4
4
|
class BitMeta(type):
|
5
|
+
"""
|
6
|
+
The BitMeta class is a constructor for Bit types.
|
7
|
+
Bit[12], for example, produces a Bit type where
|
8
|
+
W=12.
|
9
|
+
"""
|
5
10
|
|
6
11
|
def __new__(cls, name, bases, attrs):
|
7
12
|
return super().__new__(cls, name, bases, attrs)
|
@@ -15,60 +20,19 @@ class BitMeta(type):
|
|
15
20
|
return self.type_m[W]
|
16
21
|
else:
|
17
22
|
t = type("bit[%d]" % W, (Bit,), {
|
18
|
-
"
|
23
|
+
"W" : W
|
19
24
|
})
|
20
25
|
self.type_m[W] = t
|
21
26
|
return t
|
22
27
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# pass
|
35
|
-
# pass
|
36
|
-
|
37
|
-
|
38
|
-
#W = TypeVar('W')
|
39
|
-
|
40
|
-
#def bit_t(W : int) -> _GenericA[Bit[T]]:
|
41
|
-
# return Bit[Literal[W]]
|
42
|
-
|
43
|
-
#def int_t(W : int) -> Int:
|
44
|
-
# return Int[Literal[W]]
|
45
|
-
|
46
|
-
class Bits():
|
47
|
-
pass
|
48
|
-
|
49
|
-
class IntVal():
|
50
|
-
pass
|
51
|
-
|
52
|
-
class BitVal(int):
|
53
|
-
def __new__(cls, v : int, w : int):
|
54
|
-
ret = super().__new__(cls, v)
|
55
|
-
setattr(ret, "W", w)
|
56
|
-
return ret
|
57
|
-
def __getitem__(self, v):
|
58
|
-
return 5
|
59
|
-
|
60
|
-
def __add__(self, rhs):
|
61
|
-
pass
|
62
|
-
|
63
|
-
v = BitVal(5, 16)
|
64
|
-
v += 5
|
65
|
-
|
66
|
-
def bv(v : int, w : int=1) -> BitVal:
|
67
|
-
return BitVal(v, w)
|
68
|
-
|
69
|
-
a = bv(5,32)
|
70
|
-
|
71
|
-
def iv(): pass
|
72
|
-
|
73
|
-
uint64_t = Bit[Literal[64]]
|
74
|
-
#int64_t = Int[Literal[64]]
|
28
|
+
class Bit(metaclass=BitMeta):
|
29
|
+
"""
|
30
|
+
Variables of 'Bit' type represent unsigned W-bit values.
|
31
|
+
The value of the variables is automatically masked. For
|
32
|
+
example, assigning 20 (b10100) to a 4-bit variable will
|
33
|
+
result in 4 (b0100) being stored in the variable.
|
34
|
+
"""
|
35
|
+
W : int = 1
|
36
|
+
|
37
|
+
class Bits(metaclass=BitMeta):
|
38
|
+
W : int = -1
|
zuspec/dataclasses/bundle.py
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
1
16
|
from typing import Annotated, Type, TypeVar
|
2
17
|
from .decorators import dataclass
|
3
18
|
|
@@ -11,6 +26,8 @@ class Bundle(object):
|
|
11
26
|
fields are created with mirror() or field(mirror=True)
|
12
27
|
|
13
28
|
A bundle field can be connected to a mirror field.
|
29
|
+
A bundle monitor field can be connected to both a
|
30
|
+
bundle and a bundle mirror.
|
14
31
|
- Bundle
|
15
32
|
- Bundle Mirror
|
16
33
|
- Bundle Monitor (all are inputs / exports)
|
zuspec/dataclasses/component.py
CHANGED
@@ -1,6 +1,26 @@
|
|
1
|
-
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
16
|
+
import abc
|
17
|
+
from typing import TYPE_CHECKING
|
18
|
+
from .decorators import dataclass, field
|
2
19
|
from .struct import Struct
|
3
20
|
|
21
|
+
if TYPE_CHECKING:
|
22
|
+
from .std.timebase import TimeBase
|
23
|
+
|
4
24
|
@dataclass
|
5
25
|
class Component(Struct):
|
6
26
|
"""
|
@@ -15,6 +35,28 @@ class Component(Struct):
|
|
15
35
|
- constraint
|
16
36
|
- activity
|
17
37
|
"""
|
38
|
+
# def build(self): pass
|
39
|
+
|
40
|
+
@abc.abstractmethod
|
41
|
+
async def wait(self, amt : float, units):
|
42
|
+
"""
|
43
|
+
Uses the default timebase to suspend execution of the
|
44
|
+
calling coroutine for the specified time.
|
45
|
+
"""
|
46
|
+
pass
|
18
47
|
|
19
|
-
|
48
|
+
@abc.abstractmethod
|
49
|
+
async def wait_next(self, count : int = 1):
|
50
|
+
"""
|
51
|
+
Uses the default timebase to suspend execution of the
|
52
|
+
calling coroutine for the specified number of domain
|
53
|
+
evaluation events (eg clock cycles).
|
54
|
+
"""
|
55
|
+
pass
|
20
56
|
|
57
|
+
@dataclass
|
58
|
+
class ComponentExtern(Component):
|
59
|
+
"""
|
60
|
+
Extern components are used to interface with existing descriptions,
|
61
|
+
such as existing Verilog RTL.
|
62
|
+
"""
|
zuspec/dataclasses/decorators.py
CHANGED
@@ -1,33 +1,60 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# Created on Mar 19, 2022
|
17
|
+
# @author: mballance
|
18
|
+
#****************************************************************************
|
6
19
|
import dataclasses
|
7
20
|
import dataclasses as dc
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# from .impl.exec_kind_e import ExecKindE
|
13
|
-
# from .impl.extend_kind_e import ExtendKindE
|
14
|
-
# from .impl.extend_decorator_impl import ExtendDecoratorImpl
|
15
|
-
# from .impl.extend_action_decorator_impl import ExtendActionDecoratorImpl
|
16
|
-
# from .impl.extend_component_decorator_impl import ExtendComponentDecoratorImpl
|
17
|
-
# from .impl.fn_decorator_impl import FnDecoratorImpl
|
18
|
-
# from .impl.struct_decorator_impl import StructDecoratorImpl
|
19
|
-
# from .impl.struct_kind_e import StructKindE
|
20
|
-
# from .impl.component_decorator_impl import ComponentDecoratorImpl
|
21
|
-
# from .impl.activity_decorator_impl import ActivityDecoratorImpl
|
22
|
-
# from .impl.type_kind_e import TypeKindE
|
21
|
+
import enum
|
22
|
+
import inspect
|
23
|
+
import typing
|
24
|
+
from typing import Any, Callable, Dict, Optional, Self, TypeVar, TYPE_CHECKING, Union
|
23
25
|
from .annotation import Annotation, AnnotationSync
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
from .
|
26
|
+
|
27
|
+
|
28
|
+
if TYPE_CHECKING:
|
29
|
+
from .api.type_processor import TypeProcessor
|
28
30
|
|
29
31
|
def dataclass(cls, **kwargs):
|
30
|
-
|
32
|
+
# TODO: Add type annotations to decorated methods
|
33
|
+
cls_annotations = cls.__annotations__
|
34
|
+
|
35
|
+
for name, value in cls.__dict__.items():
|
36
|
+
# print("Name: %s ; Value: %s" % (name, value))
|
37
|
+
if isinstance(value, dc.Field) and not name in cls_annotations:
|
38
|
+
print("TODO: annotate field")
|
39
|
+
cls_annotations[name] = int
|
40
|
+
|
41
|
+
cls_t = dc.dataclass(cls, **kwargs)
|
42
|
+
|
43
|
+
setattr(cls_t, "__base_init__", getattr(cls_t, "__init__"))
|
44
|
+
def local_init(self, tp : 'TypeProcessor', *args, **kwargs):
|
45
|
+
"""Only called during type processing"""
|
46
|
+
return tp.init(self, *args, **kwargs)
|
47
|
+
setattr(cls_t, "__init__", local_init)
|
48
|
+
|
49
|
+
if not hasattr(cls_t, "__base_new__"):
|
50
|
+
setattr(cls_t, "__base_new__", getattr(cls_t, "__new__"))
|
51
|
+
def local_new(c, tp : 'TypeProcessor', *args, **kwargs):
|
52
|
+
"""Always called during user-object construction"""
|
53
|
+
return tp.new(c, *args, **kwargs)
|
54
|
+
setattr(cls_t, "__new__", local_new)
|
55
|
+
|
56
|
+
|
57
|
+
return cls_t
|
31
58
|
|
32
59
|
def bundle():
|
33
60
|
return dc.field()
|
@@ -98,7 +125,7 @@ a = bit(20)[3:4]
|
|
98
125
|
SelfT = TypeVar('SelfT')
|
99
126
|
T = TypeVar('T')
|
100
127
|
|
101
|
-
class bind
|
128
|
+
class bind[T]:
|
102
129
|
def __init__(self, c : Callable[[T],Dict[Any,Any]]):
|
103
130
|
self._c = c
|
104
131
|
def __call__(self, s) -> Dict[Any,Any]:
|
@@ -106,14 +133,49 @@ class bind(Generic[T]):
|
|
106
133
|
|
107
134
|
#a = bind2(lambda s:{s.}, selfT=Self)
|
108
135
|
|
109
|
-
from typing import Optional
|
110
|
-
|
111
136
|
def field(
|
112
137
|
rand=False,
|
113
|
-
width=-1,
|
114
138
|
bind : Optional[Callable[[object],Dict[Any,Any]]] = None,
|
115
|
-
|
116
|
-
|
139
|
+
init : Optional[Union[Dict[str,Any], Callable[[object],Dict[Any,Any]]]] = None,
|
140
|
+
default_factory : Optional[Any] = None,
|
141
|
+
default : Optional[Any] = None):
|
142
|
+
args = {}
|
143
|
+
metadata = None
|
144
|
+
|
145
|
+
# # Obtain the location of this call
|
146
|
+
# import inspect
|
147
|
+
# frame = inspect.currentframe()
|
148
|
+
# print("--> ")
|
149
|
+
# while frame is not None:
|
150
|
+
# modname = frame.f_globals["__name__"]
|
151
|
+
|
152
|
+
# print("modname: %s" % modname)
|
153
|
+
# if not modname.startswith("zuspec.dataclasses") and not modname.startswith("importlib"):
|
154
|
+
# break
|
155
|
+
# # pass
|
156
|
+
# # frame = frame.f_back
|
157
|
+
# else:
|
158
|
+
# frame = frame.f_back
|
159
|
+
# print("<-- ")
|
160
|
+
|
161
|
+
# if frame is not None:
|
162
|
+
# print("Location: %s:%d" % (frame.f_code.co_filename, frame.f_lineno))
|
163
|
+
|
164
|
+
if default_factory is not None:
|
165
|
+
args["default_factory"] = default_factory
|
166
|
+
|
167
|
+
if bind is not None:
|
168
|
+
metadata = {} if metadata is None else metadata
|
169
|
+
metadata["bind"] = bind
|
170
|
+
|
171
|
+
# *Always* specify a default to avoid becoming a required field
|
172
|
+
if "default_factory" not in args.keys():
|
173
|
+
args["default"] = default
|
174
|
+
|
175
|
+
if metadata is not None:
|
176
|
+
print("metadata: %s" % metadata)
|
177
|
+
args["metadata"] = metadata
|
178
|
+
return dc.field(**args)
|
117
179
|
|
118
180
|
# @staticmethod
|
119
181
|
# def __call__(rand=False, bind : Callable[[T],Dict[Any,Any]] = None):
|
@@ -127,10 +189,26 @@ def field(
|
|
127
189
|
# # TODO:
|
128
190
|
# return dc.field()
|
129
191
|
|
192
|
+
class Input(object): pass
|
193
|
+
|
194
|
+
class Output(object): pass
|
195
|
+
|
130
196
|
def input(*args, **kwargs):
|
197
|
+
"""
|
198
|
+
Marks an input field. Input fields declared on a
|
199
|
+
top-level component are `bound` to an implicit output. Those
|
200
|
+
on non-top-level components must explicitly be `bound` to an
|
201
|
+
output. An input field sees the value of the output field
|
202
|
+
to which it is bound with no delay
|
203
|
+
"""
|
131
204
|
return dataclasses.field(default_factory=Input)
|
132
205
|
|
133
206
|
def output(*args, **kwargs):
|
207
|
+
"""
|
208
|
+
Marks an output field. Input fields that are bound to
|
209
|
+
an output field always see its current output value
|
210
|
+
with no delay.
|
211
|
+
"""
|
134
212
|
return dc.field(default_factory=Output)
|
135
213
|
|
136
214
|
def lock(*args, **kwargs):
|
@@ -145,48 +223,72 @@ def port():
|
|
145
223
|
def export(*args, bind=None, **kwargs):
|
146
224
|
return dc.field(*args, **kwargs)
|
147
225
|
|
226
|
+
class ExecKind(enum.Enum):
|
227
|
+
Comb = enum.auto()
|
228
|
+
Sync = enum.auto()
|
229
|
+
Proc = enum.auto()
|
230
|
+
|
231
|
+
@dc.dataclass
|
232
|
+
class Exec(object):
|
233
|
+
method : Callable = dc.field()
|
234
|
+
kind : ExecKind = dc.field()
|
235
|
+
timebase : Optional[Callable] = field(default=None)
|
236
|
+
t : Optional[Callable] = field(default=None)
|
237
|
+
|
238
|
+
def extern(
|
239
|
+
typename,
|
240
|
+
bind,
|
241
|
+
files=None,
|
242
|
+
params=None):
|
243
|
+
"""
|
244
|
+
Denotes an instance of an external module
|
245
|
+
"""
|
246
|
+
from .struct import Extern
|
247
|
+
return dc.field(default_factory=Extern,
|
248
|
+
metadata=dict(
|
249
|
+
typename=typename,
|
250
|
+
bind=bind,
|
251
|
+
files=files,
|
252
|
+
params=params))
|
253
|
+
|
148
254
|
def process(T):
|
149
|
-
|
255
|
+
"""
|
256
|
+
Marks an always-running process. The specified
|
257
|
+
method must be `async` and take no arguments
|
258
|
+
"""
|
259
|
+
return Exec(T, ExecKind.Proc)
|
150
260
|
|
151
261
|
def reg(offset=0):
|
152
262
|
return dc.field()
|
153
263
|
pass
|
154
264
|
|
155
|
-
def const(
|
265
|
+
def const(default=None):
|
156
266
|
return dc.field()
|
157
267
|
|
158
|
-
SyncHostT = TypeVar('SyncHostT', bound=Component)
|
159
|
-
SyncMethodT = TypeVar('SyncMethodT', bound=Callable[[SyncHostT],Any])
|
160
|
-
|
161
268
|
@dc.dataclass
|
162
|
-
class
|
163
|
-
|
164
|
-
|
269
|
+
class ExecSync(Exec):
|
270
|
+
clock : Optional[Callable] = field(default=None)
|
271
|
+
reset : Optional[Callable] = field(default=None)
|
165
272
|
|
166
|
-
|
273
|
+
def sync(clock : Callable, reset : Callable):
|
274
|
+
"""
|
275
|
+
Marks a synchronous-evaluation region, which is evaluated on
|
276
|
+
the active edge of either the clock or reset.
|
277
|
+
Assignments are delayed/nonblocking, which means that only
|
278
|
+
the last assignment to a variable takes effect.
|
279
|
+
"""
|
280
|
+
def __call__(T):
|
281
|
+
return ExecSync(method=T, kind=ExecKind.Sync, clock=clock, reset=reset)
|
282
|
+
return __call__
|
167
283
|
|
168
|
-
def
|
284
|
+
def comb(latch : bool=False):
|
169
285
|
"""
|
170
|
-
|
171
|
-
|
172
|
-
each timestep (eg clock period) of the timebase. The
|
173
|
-
timebase will automatically assign the reset value
|
174
|
-
to variables assigned within the decorated method when
|
175
|
-
the timebase is reset.
|
176
|
-
A sync-decorated method may not be directly called.
|
286
|
+
Marks a combinational evaluation region that is evaluated
|
287
|
+
whenever one of the variables read by the method changes.
|
177
288
|
"""
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
# Annotation.apply(T, AnnotationSync(clock=clock, reset=reset))
|
182
|
-
# return T
|
183
|
-
# return __call__
|
184
|
-
# else:
|
185
|
-
# Annotation.apply(args[0], AnnotationSync(clock=clock, reset=reset))
|
186
|
-
# return args[0]
|
187
|
-
ret = Sync(t)
|
188
|
-
return ret
|
189
|
-
# return Sync(t)
|
289
|
+
def __call__(T):
|
290
|
+
return Exec(method=T, kind=ExecKind.Comb, )
|
291
|
+
return __call__
|
190
292
|
|
191
293
|
|
192
294
|
# def action(*args, **kwargs):
|
zuspec/dataclasses/dependency.py
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
1
16
|
import abc
|
2
17
|
import dataclasses as dc
|
3
18
|
from typing import List
|
@@ -19,4 +34,3 @@ class TrackingDependencyProvider[T](DependencyProvider):
|
|
19
34
|
List of dependencies bound to this provider
|
20
35
|
"""
|
21
36
|
pass
|
22
|
-
|
zuspec/dataclasses/ports.py
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
16
|
+
|
17
|
+
from .clock_reset import ClockReset
|
18
|
+
from .timebase import TimeBase, TimebaseSync
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
16
|
+
import abc
|
17
|
+
from ..component import Component
|
18
|
+
from ..decorators import dataclass, field, output
|
19
|
+
from ..bit import Bit
|
20
|
+
|
21
|
+
@dataclass
|
22
|
+
class ClockReset(Component):
|
23
|
+
period : int = field(default=10)
|
24
|
+
clock : Bit = output()
|
25
|
+
reset : Bit = output()
|
26
|
+
|
27
|
+
@abc.abstractmethod
|
28
|
+
def assert_reset(self): pass
|
29
|
+
|
30
|
+
@abc.abstractmethod
|
31
|
+
def release_reset(self): pass
|
32
|
+
|
33
|
+
@abc.abstractmethod
|
34
|
+
async def next(self, count : int = 1):
|
35
|
+
pass
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
# Copyright 2019-2025 Matthew Ballance and contributors
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#****************************************************************************
|
16
|
+
import abc
|
17
|
+
from typing import Protocol, TYPE_CHECKING
|
18
|
+
from ..decorators import dataclass
|
19
|
+
from ..bit import Bit
|
20
|
+
from ..component import Component
|
21
|
+
|
22
|
+
class TimeBase(Protocol):
|
23
|
+
"""
|
24
|
+
TimeBase exposes the notion of design time
|
25
|
+
"""
|
26
|
+
|
27
|
+
@abc.abstractmethod
|
28
|
+
async def wait(self, amt : float, units):
|
29
|
+
"""Scales the time to the timebase and waits"""
|
30
|
+
...
|
31
|
+
|
32
|
+
|
33
|
+
@abc.abstractmethod
|
34
|
+
def wait_ev(self, amt : float, units):
|
35
|
+
"""Scales the time to the timebase and returns an event"""
|
36
|
+
...
|
37
|
+
|
38
|
+
@dataclass
|
39
|
+
class TimebaseSync(TimeBase):
|
40
|
+
|
41
|
+
@abc.abstractmethod
|
42
|
+
async def wait_next(self, count : int = 1):
|
43
|
+
"""Waits for 'count' timebase events (eg clocks)"""
|
44
|
+
...
|
45
|
+
|
zuspec/dataclasses/struct.py
CHANGED
@@ -3,7 +3,11 @@ from typing import Dict, Optional, Type
|
|
3
3
|
from .decorators import dataclass
|
4
4
|
|
5
5
|
@dataclass
|
6
|
-
class
|
6
|
+
class ZuspecTypeBase(object):
|
7
|
+
pass
|
8
|
+
|
9
|
+
@dataclass
|
10
|
+
class StructPacked(ZuspecTypeBase):
|
7
11
|
"""
|
8
12
|
StructPacked types are fixed-size data structures.
|
9
13
|
Fields may only be of a fixed size.
|
@@ -15,7 +19,7 @@ class StructPacked(object):
|
|
15
19
|
pass
|
16
20
|
|
17
21
|
@dataclass
|
18
|
-
class Struct(
|
22
|
+
class Struct(ZuspecTypeBase):
|
19
23
|
"""
|
20
24
|
Struct types are data structures that may contain
|
21
25
|
variable-size fields.
|
@@ -26,6 +30,7 @@ class Struct(object):
|
|
26
30
|
- method
|
27
31
|
"""
|
28
32
|
|
33
|
+
|
29
34
|
# @abc.abstractmethod
|
30
35
|
# def bind[T](self, t : T):
|
31
36
|
# t : Type[T],
|
@@ -40,3 +45,5 @@ class Struct(object):
|
|
40
45
|
# pass
|
41
46
|
|
42
47
|
pass
|
48
|
+
|
49
|
+
class Extern(ZuspecTypeBase): pass
|
@@ -0,0 +1,29 @@
|
|
1
|
+
zuspec/dataclasses/__init__.py,sha256=PLcLoAnWVu-Dqz_mYg8pTZoQ3UuN_EHBnY20m7f8YDk,1353
|
2
|
+
zuspec/dataclasses/__version__.py,sha256=w6m6NGjqBy7gs-fG-V3ph2_sw4z-KMRNjIjFqN185gI,829
|
3
|
+
zuspec/dataclasses/action.py,sha256=12n8lihUhX0BFPcW370IlPgyEXLUMDSDQ_h_-rZr7ik,1328
|
4
|
+
zuspec/dataclasses/addr_reg.py,sha256=yKENXgCf9E5VEbfj0qCcJS-fwnQGdSaXG7t00aqA784,2759
|
5
|
+
zuspec/dataclasses/annotation.py,sha256=m_3h065RAR81skrq39wxsJ1V0BxpwiyAWzdTrvW51Gg,1086
|
6
|
+
zuspec/dataclasses/bit.py,sha256=qBTt8mj_S4WK6VeRaaqeNzzuvy3P12WigKaeU2Gr0mw,1072
|
7
|
+
zuspec/dataclasses/bundle.py,sha256=YIuEQS_4oS3LWQ3Zv3Ib78L6V6QzhDsd2S89BP0dsl8,1626
|
8
|
+
zuspec/dataclasses/component.py,sha256=yXSmg87uj_1TaazO99mLv72Z0lAlzzQiBTmn0wI5alo,2056
|
9
|
+
zuspec/dataclasses/decorators.py,sha256=gsVQ_84GMjfQgETH1nFK1rW4CbG6ab1yt2eJvxbo8q4,13947
|
10
|
+
zuspec/dataclasses/dependency.py,sha256=LukfqqvTUfShrtYdidqZeVMie-l50oAzkpYqo_bqie0,1289
|
11
|
+
zuspec/dataclasses/ports.py,sha256=OydeAfPIAef8pCp_3FhL87fq7mrbhiNLa9qfPHkCK1E,1044
|
12
|
+
zuspec/dataclasses/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
13
|
+
zuspec/dataclasses/struct.py,sha256=_7Lgf2BbF_WQXSpdKmowR6mATBjqZtqK6VoPPc1tdLg,1077
|
14
|
+
zuspec/dataclasses/tlm.py,sha256=sbAlnkYhVidinbiMKBT_mbe5yr1dDU9F_6aKBAXZjjE,431
|
15
|
+
zuspec/dataclasses/api/__init__.py,sha256=YwPniS7IHooW5iFCfV2MzKCVf4c4LR7--5SlGOjvGec,830
|
16
|
+
zuspec/dataclasses/api/type_processor.py,sha256=4VqIbj-Uo_DqNJpENSq8k5ll5TxhRFlLjq5Psi0Ss7I,956
|
17
|
+
zuspec/dataclasses/api/visitor.py,sha256=CduJ6k11xY81_nFl8k0dVSRJt88a21mHem64Yeg6sDI,11852
|
18
|
+
zuspec/dataclasses/std/__init__.py,sha256=7xOZCDuEikfg5NRpC0eFGIvgj3hHz7ibtJawzroU4nY,839
|
19
|
+
zuspec/dataclasses/std/clock_reset.py,sha256=AveFnqB-OAgWfVr2eA7v9XfAPuE12WtQpSbbE1zhwME,1205
|
20
|
+
zuspec/dataclasses/std/timebase.py,sha256=kgkeJ52jHvngdcs8lw5bJ20NDhWmzcAlRmPQ11Qa96A,1468
|
21
|
+
zuspec/dataclasses/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
+
zuspec/dataclasses/util/extract_cpp_embedded_dsl.py,sha256=SyMMLumZD6fsubj40hyekYzWyrcoUGTijJH3NmK1ihY,5630
|
23
|
+
zuspec/dataclasses/util/gen_cpp_dt_defs/__main__.py,sha256=t3CnHJKcN_N33sxCsDH-R36ghCcQ7xjMcjUrzUT2SGM,3447
|
24
|
+
zuspec/impl/__init__.py,sha256=GZWCeBPdVzLR0RNPkmXNXPgdS-2vg5dMC1goTYJs3yI,33
|
25
|
+
zuspec_dataclasses-0.0.1.18247373596rc0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
26
|
+
zuspec_dataclasses-0.0.1.18247373596rc0.dist-info/METADATA,sha256=O74TphkBnh2iHRNubkDsL_at148MqH3qS_f-HGXQwKY,121
|
27
|
+
zuspec_dataclasses-0.0.1.18247373596rc0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
28
|
+
zuspec_dataclasses-0.0.1.18247373596rc0.dist-info/top_level.txt,sha256=3WM_V5g1RvpI4_z1TPY_AmroKhWIp6QJo4Vz5Tqbgak,7
|
29
|
+
zuspec_dataclasses-0.0.1.18247373596rc0.dist-info/RECORD,,
|
zuspec/dataclasses/clock.py
DELETED
zuspec/dataclasses/reset.py
DELETED
zuspec/dataclasses/timebase.py
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
import abc
|
2
|
-
from .component import Component
|
3
|
-
from .decorators import dataclass, input
|
4
|
-
from .bit import Bit
|
5
|
-
|
6
|
-
@dataclass
|
7
|
-
class TimeBase(object):
|
8
|
-
"""
|
9
|
-
TimeBase exposes the notion of design time
|
10
|
-
"""
|
11
|
-
|
12
|
-
@abc.abstractmethod
|
13
|
-
async def wait(self, amt : float, units):
|
14
|
-
"""Scales the time to the timebase and waits"""
|
15
|
-
pass
|
16
|
-
|
17
|
-
@abc.abstractmethod
|
18
|
-
def wait_ev(self, amt : float, units):
|
19
|
-
"""Scales the time to the timebase and returns an event"""
|
20
|
-
pass
|
21
|
-
|
22
|
-
pass
|
23
|
-
|
24
|
-
class TimeBaseSignal(TimeBase,Component):
|
25
|
-
clock : Bit = input()
|
26
|
-
reset : Bit = input()
|
27
|
-
|
@@ -1,28 +0,0 @@
|
|
1
|
-
zuspec/dataclasses/__init__.py,sha256=-a466Myi0Gs7JWbIm2LiNKkHFuIjoGsjj5aMrAyQuBs,462
|
2
|
-
zuspec/dataclasses/__version__.py,sha256=2pHn0_iz8uobg16bUlzrP3GDosLHvXeTtklooC9fUFo,71
|
3
|
-
zuspec/dataclasses/action.py,sha256=z7aMc6e_k_-NCzYDm8K1ymEPfcGeyqlO79of0Gucack,570
|
4
|
-
zuspec/dataclasses/addr_reg.py,sha256=14dgTvdkyHxzGLOJRqMkAFwKhnRM2iI3B6IdzioJQl8,1728
|
5
|
-
zuspec/dataclasses/annotation.py,sha256=M41iS93Oi8M-ER_ZIBI8CIWJ1bvEMI0nHa-RxbmWJUs,328
|
6
|
-
zuspec/dataclasses/bit.py,sha256=PHGjvh-O4k7m-juXQzEMZJIn5k-h1cJaIHmgk0RhofM,1405
|
7
|
-
zuspec/dataclasses/bundle.py,sha256=6fqjfoTS_-_izl4FlPFgurfOg3tnj_1fmEdSa1FF4C0,781
|
8
|
-
zuspec/dataclasses/clock.py,sha256=pM0rO-3bp0SGJccxtU-17vIcF9EaSlqD-q1_9O0of1o,30
|
9
|
-
zuspec/dataclasses/component.py,sha256=oERqTHRdiI2oYW5q8ijYNY9FUMIrqLlqAVfZFipjzPU,524
|
10
|
-
zuspec/dataclasses/decorators.py,sha256=v6toBLONKbw5dj7DRoH9XEOSNghBNjuRWjc1C66LEHc,10762
|
11
|
-
zuspec/dataclasses/dependency.py,sha256=kGxdFqKlviUP7qmvN-FbnXIiqCPdgRRel83feuu8OoU,532
|
12
|
-
zuspec/dataclasses/ports.py,sha256=3pbBwdBzDMAJTZ15Qf6sSXB-XOH5cJ-G5H8kQa5JurQ,1106
|
13
|
-
zuspec/dataclasses/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
14
|
-
zuspec/dataclasses/reset.py,sha256=DV8tiKq_k-AGUNBbpJCJFx_EEfA07UgUJK2veYli0b0,30
|
15
|
-
zuspec/dataclasses/struct.py,sha256=vId0487ZJmhnTbTg421B-iN9PtxNexCv9DMqRO8RXBU,973
|
16
|
-
zuspec/dataclasses/timebase.py,sha256=rjEiGB2lNPMTewE-Z4iX-CHnbx1QVTUbtwEXnKMkesI,599
|
17
|
-
zuspec/dataclasses/tlm.py,sha256=sbAlnkYhVidinbiMKBT_mbe5yr1dDU9F_6aKBAXZjjE,431
|
18
|
-
zuspec/dataclasses/api/__init__.py,sha256=HfJhJ_B1RJSpJn5NmWzEK3l2IruubiEKd3xwLDuED6Q,30
|
19
|
-
zuspec/dataclasses/api/visitor.py,sha256=8-5er0GxAWnvxhDmiR_OBn2iMxtymtol5qM09ucKdLI,1780
|
20
|
-
zuspec/dataclasses/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
|
-
zuspec/dataclasses/util/extract_cpp_embedded_dsl.py,sha256=SyMMLumZD6fsubj40hyekYzWyrcoUGTijJH3NmK1ihY,5630
|
22
|
-
zuspec/dataclasses/util/gen_cpp_dt_defs/__main__.py,sha256=t3CnHJKcN_N33sxCsDH-R36ghCcQ7xjMcjUrzUT2SGM,3447
|
23
|
-
zuspec/impl/__init__.py,sha256=GZWCeBPdVzLR0RNPkmXNXPgdS-2vg5dMC1goTYJs3yI,33
|
24
|
-
zuspec_dataclasses-0.0.1.17516204125rc0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
25
|
-
zuspec_dataclasses-0.0.1.17516204125rc0.dist-info/METADATA,sha256=i1hPXCIb3njC6aXg7B4-7PEyGQFnISQB-cg4W36qFtY,121
|
26
|
-
zuspec_dataclasses-0.0.1.17516204125rc0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
27
|
-
zuspec_dataclasses-0.0.1.17516204125rc0.dist-info/top_level.txt,sha256=3WM_V5g1RvpI4_z1TPY_AmroKhWIp6QJo4Vz5Tqbgak,7
|
28
|
-
zuspec_dataclasses-0.0.1.17516204125rc0.dist-info/RECORD,,
|
File without changes
|
File without changes
|