Skip to content

Commit 84561c9

Browse files
authored
Merge pull request cmsis-svd#56 from stefanhoelzl/cluster-support
Cluster support
2 parents dbc4f1a + 0991d8f commit 84561c9

File tree

4 files changed

+323
-5
lines changed

4 files changed

+323
-5
lines changed

python/cmsis_svd/model.py

Lines changed: 168 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,165 @@ def is_reserved(self):
282282
return 'reserved' in self.name.lower()
283283

284284

285+
class SVDRegisterCluster(SVDElement):
286+
"""Represent a register cluster in the tree"""
287+
288+
def __init__(self, name, derived_from, description, address_offset, size,
289+
alternate_cluster, header_struct_name,
290+
access, protection, reset_value, reset_mask, register,
291+
cluster):
292+
SVDElement.__init__(self)
293+
294+
# When deriving a register, it is mandatory to specify at least the name, the description,
295+
# and the addressOffset
296+
self.derived_from = derived_from
297+
self.name = name
298+
self.description = description
299+
self.address_offset = address_offset
300+
301+
self._alternate_cluster = alternate_cluster
302+
self._header_struct_name = header_struct_name
303+
self._size = size
304+
self._access = access
305+
self._protection = protection
306+
self._reset_value = reset_value
307+
self._reset_mask = reset_mask
308+
self._register = register
309+
self._cluster = cluster
310+
311+
# make parent association
312+
for cluster in self._cluster:
313+
cluster.parent = self
314+
315+
def __getattr__(self, attr):
316+
return self._lookup_possibly_derived_attribute(attr)
317+
318+
def updated_register(self, reg, clu):
319+
new_reg = SVDRegister(
320+
name="{}_{}".format(clu.name, reg.name),
321+
fields=reg.fields,
322+
derived_from=reg.derived_from,
323+
description=reg.description,
324+
address_offset=clu.address_offset + reg.address_offset,
325+
size=reg.size,
326+
access=reg.access,
327+
protection=reg.protection,
328+
reset_value=reg.reset_value,
329+
reset_mask=reg.reset_mask,
330+
display_name=reg.display_name,
331+
alternate_group=reg.alternate_group,
332+
modified_write_values=reg.modified_write_values,
333+
read_action=reg.read_action,
334+
)
335+
new_reg.parent = self
336+
return new_reg
337+
338+
@property
339+
def registers(self):
340+
for reg in self._register:
341+
yield self.updated_register(reg, self)
342+
for cluster in self._cluster:
343+
for reg in cluster.registers:
344+
yield self.updated_register(reg, self)
345+
346+
def get_derived_from(self):
347+
# TODO: add support for dot notation derivedFrom
348+
if self.derived_from is None:
349+
return None
350+
351+
for register in self.parent.registers:
352+
if register.name == self.derived_from:
353+
return register
354+
355+
raise KeyError("Unable to find derived_from: %r" % self.derived_from)
356+
357+
def is_reserved(self):
358+
return 'reserved' in self.name.lower()
359+
360+
361+
class SVDRegisterClusterArray(SVDElement):
362+
"""Represent a register cluster in the tree"""
363+
364+
def __init__(self, name, derived_from, description, address_offset, size,
365+
alternate_cluster, header_struct_name,
366+
dim, dim_indices, dim_increment,
367+
access, protection, reset_value, reset_mask, register,
368+
cluster):
369+
SVDElement.__init__(self)
370+
371+
# When deriving a register, it is mandatory to specify at least the name, the description,
372+
# and the addressOffset
373+
self.derived_from = derived_from
374+
self.name = name
375+
self.description = description
376+
self.address_offset = address_offset
377+
self.dim = dim
378+
self.dim_indices = dim_indices
379+
self.dim_increment = dim_increment
380+
381+
self._alternate_cluster = alternate_cluster
382+
self._header_struct_name = header_struct_name
383+
self._size = size
384+
self._access = access
385+
self._protection = protection
386+
self._reset_value = reset_value
387+
self._reset_mask = reset_mask
388+
self._register = register
389+
self._cluster = cluster
390+
391+
# make parent association
392+
for register in self._register:
393+
register.parent = self
394+
for cluster in self._cluster:
395+
cluster.parent = self
396+
397+
def __getattr__(self, attr):
398+
return self._lookup_possibly_derived_attribute(attr)
399+
400+
def updated_register(self, reg, clu, i):
401+
new_reg = SVDRegister(
402+
name="{}_{}".format(clu.name % i, reg.name),
403+
fields=reg.fields,
404+
derived_from=reg.derived_from,
405+
description=reg.description,
406+
address_offset=clu.address_offset + reg.address_offset + i*clu.dim_increment,
407+
size=reg.size,
408+
access=reg.access,
409+
protection=reg.protection,
410+
reset_value=reg.reset_value,
411+
reset_mask=reg.reset_mask,
412+
display_name=reg.display_name,
413+
alternate_group=reg.alternate_group,
414+
modified_write_values=reg.modified_write_values,
415+
read_action=reg.read_action,
416+
)
417+
new_reg.parent = self
418+
return new_reg
419+
420+
@property
421+
def registers(self):
422+
for i in six.moves.range(self.dim):
423+
for reg in self._register:
424+
yield self.updated_register(reg, self, i)
425+
for cluster in self._cluster:
426+
for reg in cluster.registers:
427+
yield self.updated_register(reg, cluster, i)
428+
429+
def get_derived_from(self):
430+
# TODO: add support for dot notation derivedFrom
431+
if self.derived_from is None:
432+
return None
433+
434+
for register in self.parent.registers:
435+
if register.name == self.derived_from:
436+
return register
437+
438+
raise KeyError("Unable to find derived_from: %r" % self.derived_from)
439+
440+
def is_reserved(self):
441+
return 'reserved' in self.name.lower()
442+
443+
285444
class SVDAddressBlock(SVDElement):
286445
def __init__(self, offset, size, usage):
287446
SVDElement.__init__(self)
@@ -298,9 +457,12 @@ def __init__(self, name, value):
298457

299458

300459
class SVDPeripheral(SVDElement):
301-
def __init__(self, name, version, derived_from, description, prepend_to_name, base_address, address_block,
302-
interrupts, registers, register_arrays, size, access, protection, reset_value, reset_mask,
303-
group_name, append_to_name, disable_condition):
460+
def __init__(self, name, version, derived_from, description,
461+
prepend_to_name, base_address, address_block,
462+
interrupts, registers, register_arrays, size, access,
463+
protection, reset_value, reset_mask,
464+
group_name, append_to_name, disable_condition,
465+
clusters):
304466
SVDElement.__init__(self)
305467

306468
# items with underscore are potentially derived
@@ -322,6 +484,7 @@ def __init__(self, name, version, derived_from, description, prepend_to_name, ba
322484
self._group_name = group_name
323485
self._append_to_name = append_to_name
324486
self._disable_condition = disable_condition
487+
self._clusters = clusters
325488

326489
# make parent association for complex node types
327490
for i in _none_as_empty(self._interrupts):
@@ -339,6 +502,8 @@ def registers(self):
339502
regs.append(reg)
340503
for arr in self._lookup_possibly_derived_attribute('register_arrays'):
341504
regs.extend(arr.registers)
505+
for cluster in self._lookup_possibly_derived_attribute('clusters'):
506+
regs.extend(cluster.registers)
342507
return regs
343508

344509
def get_derived_from(self):

python/cmsis_svd/parser.py

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717

1818
import six
1919

20-
from cmsis_svd.model import SVDDevice, SVDRegisterArray
20+
from cmsis_svd.model import SVDDevice
2121
from cmsis_svd.model import SVDPeripheral
2222
from cmsis_svd.model import SVDInterrupt
2323
from cmsis_svd.model import SVDAddressBlock
24-
from cmsis_svd.model import SVDRegister
24+
from cmsis_svd.model import SVDRegister, SVDRegisterArray
25+
from cmsis_svd.model import SVDRegisterCluster, SVDRegisterClusterArray
2526
from cmsis_svd.model import SVDField
2627
from cmsis_svd.model import SVDEnumeratedValue
2728
from cmsis_svd.model import SVDCpu
@@ -224,6 +225,76 @@ def _parse_registers(self, register_node):
224225
dim_increment=dim_increment,
225226
)
226227

228+
def _parse_cluster(self, cluster_node):
229+
dim = _get_int(cluster_node, 'dim')
230+
name = _get_text(cluster_node, 'name')
231+
derived_from = _get_text(cluster_node, 'derivedFrom')
232+
description = _get_text(cluster_node, 'description')
233+
address_offset = _get_int(cluster_node, 'addressOffset')
234+
size = _get_int(cluster_node, 'size')
235+
access = _get_text(cluster_node, 'access')
236+
protection = _get_text(cluster_node, 'protection')
237+
reset_value = _get_int(cluster_node, 'resetValue')
238+
reset_mask = _get_int(cluster_node, 'resetMask')
239+
dim_increment = _get_int(cluster_node, 'dimIncrement')
240+
dim_index_text = _get_text(cluster_node, 'dimIndex')
241+
alternate_cluster = _get_text(cluster_node, 'alternateGluster')
242+
header_struct_name = _get_text(cluster_node, 'headerStructName')
243+
cluster = []
244+
for sub_cluster_node in cluster_node.findall("./cluster"):
245+
cluster.append(self._parse_cluster(sub_cluster_node))
246+
register = []
247+
for reg_node in cluster_node.findall("./register"):
248+
register.append(self._parse_registers(reg_node))
249+
250+
if dim is None:
251+
return SVDRegisterCluster(
252+
name=name,
253+
derived_from=derived_from,
254+
description=description,
255+
address_offset=address_offset,
256+
size=size,
257+
access=access,
258+
protection=protection,
259+
reset_value=reset_value,
260+
reset_mask=reset_mask,
261+
alternate_cluster=alternate_cluster,
262+
header_struct_name=header_struct_name,
263+
register=register,
264+
cluster=cluster,
265+
)
266+
else:
267+
# the node represents a register array
268+
if dim_index_text is None:
269+
dim_indices = range(0, dim) # some files omit dimIndex
270+
elif ',' in dim_index_text:
271+
dim_indices = dim_index_text.split(',')
272+
elif '-' in dim_index_text: # some files use <dimIndex>0-3</dimIndex> as an inclusive inclusive range
273+
m = re.search(r'([0-9]+)-([0-9]+)', dim_index_text)
274+
dim_indices = range(int(m.group(1)), int(m.group(2)) + 1)
275+
else:
276+
raise ValueError("Unexpected dim_index_text: %r" % dim_index_text)
277+
278+
# yield `SVDRegisterArray` (caller will differentiate on type)
279+
return SVDRegisterClusterArray(
280+
name=name,
281+
derived_from=derived_from,
282+
description=description,
283+
address_offset=address_offset,
284+
size=size,
285+
access=access,
286+
protection=protection,
287+
reset_value=reset_value,
288+
reset_mask=reset_mask,
289+
alternate_cluster=alternate_cluster,
290+
header_struct_name=header_struct_name,
291+
register=register,
292+
cluster=cluster,
293+
dim=dim,
294+
dim_increment=dim_increment,
295+
dim_indices=dim_indices,
296+
)
297+
227298
def _parse_address_block(self, address_block_node):
228299
return SVDAddressBlock(
229300
_get_int(address_block_node, 'offset'),
@@ -248,6 +319,11 @@ def _parse_peripheral(self, peripheral_node):
248319
else:
249320
registers.append(reg)
250321

322+
clusters = []
323+
for cluster_node in peripheral_node.findall('./registers/cluster'):
324+
reg = self._parse_cluster(cluster_node)
325+
clusters.append(reg)
326+
251327
# parse all interrupts for the peripheral
252328
interrupts = []
253329
for interrupt_node in peripheral_node.findall('./interrupt'):
@@ -311,6 +387,11 @@ def _parse_peripheral(self, peripheral_node):
311387
register_arrays=register_arrays,
312388
registers=registers,
313389

390+
# <cluster>
391+
# ...
392+
# </cluster>
393+
clusters=clusters,
394+
314395
# (not mentioned in docs -- applies to all registers)
315396
protection=_get_text(peripheral_node, 'protection'),
316397
)

0 commit comments

Comments
 (0)