-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathimporter.py
353 lines (301 loc) · 12.8 KB
/
importer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
from typing import Optional, Any, List, TYPE_CHECKING
import re
from .compiler import RDLCompiler
from .source_ref import FileSourceRef, SourceRefBase
from . import component as comp
if TYPE_CHECKING:
from typing import TypeVar, Type
ComponentClass = TypeVar('ComponentClass', bound=comp.Component)
AddressableComponentClass = TypeVar('AddressableComponentClass', bound=comp.AddressableComponent)
class RDLImporter:
def __init__(self, compiler: RDLCompiler):
"""
Base class for external parsers to import data into the register model
Parameters
----------
compiler: :class:`RDLCompiler`
Reference to compiler instance where the import is being performed.
"""
#: Reference to the current compiler instance
self.compiler = compiler
#: Reference to the compiler message handler
#:
#: .. warning::
#:
#: This will be deprecated in a future release. See this page for more details: https://github.com/SystemRDL/systemrdl-compiler/issues/168
self.msg = compiler.env.msg
#: Source reference used by default when not specified in importer
#: model construction methods
#: By default, this simply points to the file currently being imported,
#: without any line offset information
self.default_src_ref = None # type: SourceRefBase
def import_file(self, path: str) -> None:
"""
Importer entry point.
Extend this function to read the file and perform the import.
Be sure to call ``super().import_file(path)``
Parameters
----------
path: str
Path to file
"""
self.default_src_ref = FileSourceRef(path)
# ------------------------ create_xxx_definition() -------------------------
def _create_definition(self, cls: "Type[ComponentClass]", type_name: Optional[str] = None, src_ref: Optional[SourceRefBase] = None) -> "ComponentClass":
if (type_name is not None) and not re.fullmatch(r"[a-zA-Z_]\w*", type_name):
raise ValueError("Type name has invalid characters: '%s'" % type_name)
C = cls()
C.type_name = type_name
C.def_src_ref = src_ref or self.default_src_ref
return C
def create_field_definition(self, type_name: Optional[str] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Field:
"""
Parameters
----------
type_name: str
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Field`
Component definition
"""
return self._create_definition(comp.Field, type_name, src_ref)
def create_reg_definition(self, type_name: Optional[str] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Reg:
"""
Parameters
----------
type_name: str
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Reg`
Component definition
"""
return self._create_definition(comp.Reg, type_name, src_ref)
def create_regfile_definition(self, type_name: Optional[str] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Regfile:
"""
Parameters
----------
type_name: str
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Regfile`
Component definition
"""
return self._create_definition(comp.Regfile, type_name, src_ref)
def create_addrmap_definition(self, type_name: Optional[str] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Addrmap:
"""
Parameters
----------
type_name: str
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Addrmap`
Component definition
"""
return self._create_definition(comp.Addrmap, type_name, src_ref)
def create_mem_definition(self, type_name: Optional[str] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Mem:
"""
Parameters
----------
type_name: str
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Mem`
Component definition
"""
C = self._create_definition(comp.Mem, type_name, src_ref)
C.external = True
return C
# --------------------------- instantiate_xxx() ----------------------------
def _instantiate(self, comp_def: "ComponentClass", inst_name: str, src_ref: Optional[SourceRefBase] = None) -> "ComponentClass":
if comp_def.is_instance:
raise ValueError("Component is already instantiated")
if not re.fullmatch(r"[a-zA-Z_]\w*", inst_name):
raise ValueError("Instance name has invalid characters: '%s'" % inst_name)
if comp_def.type_name is None:
# anonymous definition. No need to copy since it can only be used once
comp_inst = comp_def
else:
# named definition. Copy so that the definition can be re-used
comp_inst = comp_def._copy_for_inst({})
comp_inst.original_def = comp_def
comp_inst.is_instance = True
comp_inst.inst_name = inst_name
comp_inst.inst_src_ref = src_ref or self.default_src_ref
return comp_inst
def instantiate_field(self, comp_def: comp.Field, inst_name: str, bit_offset: int, bit_width: int, src_ref: Optional[SourceRefBase] = None) -> comp.Field:
"""
Parameters
----------
comp_def: :class:`comp.Field`
inst_name: str
bit_offset: int
bit_width: int
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Field`
Component instance
"""
assert isinstance(comp_def, comp.Field)
comp_inst = self._instantiate(comp_def, inst_name, src_ref)
comp_inst.low = bit_offset
comp_inst.high = bit_offset + bit_width - 1
comp_inst.lsb = comp_inst.low
comp_inst.msb = comp_inst.high
comp_inst.width = bit_width
return comp_inst
def _instantiate_addressable(self, comp_def: "AddressableComponentClass", inst_name: str, addr_offset: int, array_dimensions: Optional[List[int]] = None, array_stride: Optional[int] = None, src_ref: Optional[SourceRefBase] = None) -> "AddressableComponentClass":
comp_inst = self._instantiate(comp_def, inst_name, src_ref)
comp_inst.addr_offset = addr_offset
if array_dimensions:
comp_inst.is_array = True
comp_inst.array_dimensions = array_dimensions
comp_inst.array_stride = array_stride
return comp_inst
def instantiate_reg(self, comp_def: comp.Reg, inst_name: str, addr_offset: int, array_dimensions: Optional[List[int]] = None, array_stride: Optional[int] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Reg:
"""
Parameters
----------
comp_def: :class:`comp.Reg`
inst_name: str
addr_offset: int
array_dimensions: int
array_stride: int
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Field`
Component instance
"""
assert isinstance(comp_def, comp.Reg)
return self._instantiate_addressable(comp_def, inst_name, addr_offset, array_dimensions, array_stride, src_ref)
def instantiate_regfile(self, comp_def: comp.Regfile, inst_name: str, addr_offset: int, array_dimensions: Optional[List[int]] = None, array_stride: Optional[int] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Regfile:
"""
Parameters
----------
comp_def: :class:`comp.Regfile`
inst_name: str
addr_offset: int
array_dimensions: int
array_stride: int
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Field`
Component instance
"""
assert isinstance(comp_def, comp.Regfile)
return self._instantiate_addressable(comp_def, inst_name, addr_offset, array_dimensions, array_stride, src_ref)
def instantiate_addrmap(self, comp_def: comp.Addrmap, inst_name: str, addr_offset: int, array_dimensions: Optional[List[int]] = None, array_stride: Optional[int] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Addrmap:
"""
Parameters
----------
comp_def: :class:`comp.Addrmap`
inst_name: str
addr_offset: int
array_dimensions: int
array_stride: int
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Field`
Component instance
"""
assert isinstance(comp_def, comp.Addrmap)
return self._instantiate_addressable(comp_def, inst_name, addr_offset, array_dimensions, array_stride, src_ref)
def instantiate_mem(self, comp_def: comp.Mem, inst_name: str, addr_offset: int, array_dimensions: Optional[List[int]] = None, array_stride: Optional[int] = None, src_ref: Optional[SourceRefBase] = None) -> comp.Mem:
"""
Parameters
----------
comp_def: :class:`comp.Mem`
inst_name: str
addr_offset: int
array_dimensions: int
array_stride: int
src_ref: :class:`~SourceRefBase`
Returns
-------
:class:`~comp.Field`
Component instance
"""
assert isinstance(comp_def, comp.Mem)
return self._instantiate_addressable(comp_def, inst_name, addr_offset, array_dimensions, array_stride, src_ref)
#---------------------------------------------------------------------------
def add_child(self, parent: comp.Component, child: comp.Component) -> None:
"""
Add a child component instance to an existing parent definition or instance
.. versionadded:: 1.16
"""
bad = True
if isinstance(parent, comp.Addrmap):
if isinstance(child, comp.AddressableComponent):
bad = False
elif isinstance(parent, comp.Regfile):
if isinstance(child, (comp.Regfile, comp.Reg)):
bad = False
elif isinstance(parent, comp.Mem):
if isinstance(child, comp.Reg):
bad = False
elif isinstance(parent, comp.Reg):
if isinstance(child, comp.Field):
bad = False
if bad:
raise TypeError("Parent %s cannot be assigned child %s" % (repr(parent), repr(child)))
if not child.is_instance:
raise ValueError("Child must be an instance if adding to a parent")
parent.children.append(child)
def assign_property(self, component: comp.Component, prop_name: str, value: Any, src_ref: Optional[SourceRefBase] = None) -> None:
"""
Assign a property to a component.
Parameters
----------
prop_name: str
Name of the SystemRDL property
value:
Value to assign
src_ref: :class:`~SourceRefBase`
Optionally provide a more detailed source reference object associated
with this assignment
"""
rule = self.compiler.env.property_rules.lookup_property(prop_name)
if rule is None:
raise ValueError("Unrecognized property '%s'" % prop_name)
if isinstance(value, comp.Component):
# Warn user that this is not how references work
raise TypeError("Invalid assignment type")
src_ref = src_ref or self.default_src_ref
rule.assign_value(component, value, src_ref)
def register_root_component(self, definition: comp.Component) -> None:
"""
Register a component definition with the root namespace so that it is
visible to other compiled files.
Parameters
----------
definition: :class:`comp.Component`
Component definition to register
"""
if definition.type_name is None:
raise ValueError("Component must have a type_name")
if definition.is_instance:
raise ValueError("Component cannot already be instantiated")
if len(self.compiler.namespace.type_ns_stack) != 1:
raise RuntimeError("Namespace was not properly reset to root scope")
# Register with namespace
self.compiler.namespace.register_type(
definition.type_name,
definition,
definition.def_src_ref
)
# Add to root component definition list
self.compiler.root.comp_defs[definition.type_name] = definition
def lookup_root_component(self, type_name: str) -> Optional[comp.Component]:
"""
Lookup a component definition from the root namespace. If the type name
is not defined, returns ``None``
"""
return self.compiler.root.comp_defs.get(type_name, None)