tinyriscv/tools/regtool/reggen/clocking.py

95 lines
3.2 KiB
Python

# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
'''Code representing clocking or resets for an IP block'''
from typing import Dict, List, Optional
from .lib import check_keys, check_list, check_bool, check_optional_name
class ClockingItem:
def __init__(self, clock: Optional[str], reset: Optional[str], primary: bool):
if primary:
assert clock is not None
assert reset is not None
self.clock = clock
self.reset = reset
self.primary = primary
@staticmethod
def from_raw(raw: object, only_item: bool, where: str) -> 'ClockingItem':
what = f'clocking item at {where}'
rd = check_keys(raw, what, [], ['clock', 'reset', 'primary'])
clock = check_optional_name(rd.get('clock'), 'clock field of ' + what)
reset = check_optional_name(rd.get('reset'), 'reset field of ' + what)
primary = check_bool(rd.get('primary', only_item),
'primary field of ' + what)
if primary:
if clock is None:
raise ValueError('No clock signal for primary '
f'clocking item at {what}.')
if reset is None:
raise ValueError('No reset signal for primary '
f'clocking item at {what}.')
return ClockingItem(clock, reset, primary)
def _asdict(self) -> Dict[str, object]:
ret = {} # type: Dict[str, object]
if self.clock is not None:
ret['clock'] = self.clock,
if self.reset is not None:
ret['reset'] = self.reset
ret['primary'] = self.primary
return ret
class Clocking:
def __init__(self, items: List[ClockingItem], primary: ClockingItem):
assert items
self.items = items
self.primary = primary
@staticmethod
def from_raw(raw: object, where: str) -> 'Clocking':
what = f'clocking items at {where}'
raw_items = check_list(raw, what)
if not raw_items:
raise ValueError(f'Empty list of clocking items at {where}.')
just_one_item = len(raw_items) == 1
items = []
primaries = []
for idx, raw_item in enumerate(raw_items):
item_where = f'entry {idx} of {what}'
item = ClockingItem.from_raw(raw_item, just_one_item, item_where)
if item.primary:
primaries.append(item)
items.append(item)
if len(primaries) != 1:
raise ValueError('There should be exactly one primary clocking '
f'item at {where}, but we saw {len(primaries)}.')
return Clocking(items, primaries[0])
def other_clocks(self) -> List[str]:
ret = []
for item in self.items:
if not item.primary and item.clock is not None:
ret.append(item.clock)
return ret
def clock_signals(self) -> List[str]:
return [item.clock for item in self.items if item.clock is not None]
def reset_signals(self) -> List[str]:
return [item.reset for item in self.items if item.reset is not None]