Files
PeakRDL-regblock/peakrdl/regblock/field_logic/field_builder.py
2021-12-04 17:31:12 -08:00

177 lines
6.8 KiB
Python

from typing import TYPE_CHECKING
from collections import OrderedDict
from systemrdl.rdltypes import PrecedenceType
from .bases import AssignmentPrecedence, NextStateConditional
from . import sw_onread
from . import sw_onwrite
from ..struct_generator import RDLStructGenerator
from ..forloop_generator import RDLForLoopGenerator
from ..utils import get_indexed_path, get_always_ff_event
from ..signals import RDLSignal
if TYPE_CHECKING:
from typing import Dict, List
from systemrdl.node import FieldNode, AddrmapNode
from ..exporter import RegblockExporter
class FieldBuilder:
def __init__(self, exporter:'RegblockExporter'):
self.exporter = exporter
self._hw_conditionals = {} # type: Dict[int, List[NextStateConditional]]
self._sw_conditionals = {} # type: Dict[int, List[NextStateConditional]]
self.init_conditionals()
@property
def top_node(self) -> 'AddrmapNode':
return self.exporter.top_node
def add_hw_conditional(self, conditional: NextStateConditional, precedence: AssignmentPrecedence) -> None:
# TODO: Add docstring!
if precedence not in self._hw_conditionals:
self._hw_conditionals[precedence] = []
self._hw_conditionals[precedence].append(conditional)
def add_sw_conditional(self, conditional: NextStateConditional, precedence: AssignmentPrecedence) -> None:
# TODO: Add docstring!
if precedence not in self._sw_conditionals:
self._sw_conditionals[precedence] = []
self._sw_conditionals[precedence].append(conditional)
def init_conditionals(self) -> None:
# TODO: Add docstring!
# TODO: Add all the other things
self.add_sw_conditional(sw_onread.ClearOnRead(self.exporter), AssignmentPrecedence.SW_ONREAD)
self.add_sw_conditional(sw_onread.SetOnRead(self.exporter), AssignmentPrecedence.SW_ONREAD)
self.add_hw_conditional(sw_onwrite.WriteOneSet(self.exporter), AssignmentPrecedence.SW_ONWRITE)
self.add_hw_conditional(sw_onwrite.WriteOneClear(self.exporter), AssignmentPrecedence.SW_ONWRITE)
self.add_hw_conditional(sw_onwrite.WriteOneToggle(self.exporter), AssignmentPrecedence.SW_ONWRITE)
self.add_hw_conditional(sw_onwrite.WriteZeroSet(self.exporter), AssignmentPrecedence.SW_ONWRITE)
self.add_hw_conditional(sw_onwrite.WriteZeroClear(self.exporter), AssignmentPrecedence.SW_ONWRITE)
self.add_hw_conditional(sw_onwrite.WriteZeroToggle(self.exporter), AssignmentPrecedence.SW_ONWRITE)
self.add_hw_conditional(sw_onwrite.WriteClear(self.exporter), AssignmentPrecedence.SW_ONWRITE)
self.add_hw_conditional(sw_onwrite.WriteSet(self.exporter), AssignmentPrecedence.SW_ONWRITE)
self.add_hw_conditional(sw_onwrite.Write(self.exporter), AssignmentPrecedence.SW_ONWRITE)
def _get_X_conditionals(self, conditionals: 'Dict[int, List[NextStateConditional]]', field: 'FieldNode') -> 'List[NextStateConditional]':
result = []
precedences = sorted(conditionals.keys(), reverse=True)
for precedence in precedences:
for conditional in conditionals[precedence]:
if conditional.is_match(field):
result.append(conditional)
return result
def get_conditionals(self, field: 'FieldNode') -> 'List[NextStateConditional]':
# TODO: Add docstring! - list of NextStateConditional. Highest precedence comes first
sw_precedence = (field.get_property('precedence') == PrecedenceType.sw)
result = []
if sw_precedence:
result.extend(self._get_X_conditionals(self._sw_conditionals, field))
result.extend(self._get_X_conditionals(self._hw_conditionals, field))
if not sw_precedence:
result.extend(self._get_X_conditionals(self._sw_conditionals, field))
return result
class CombinationalStructGenerator(RDLStructGenerator):
def __init__(self, field_builder: FieldBuilder):
super().__init__()
self.field_builder = field_builder
def enter_Field(self, node: 'FieldNode') -> None:
# If a field doesn't implement storage, it is not relevant here
if not node.implements_storage:
return
# collect any extra combo signals that this field requires
extra_combo_signals = OrderedDict()
for conditional in self.field_builder.get_conditionals(node):
for signal in conditional.get_extra_combo_signals(node):
if signal.name in extra_combo_signals:
# Assert that subsequent declarations of the same signal
# are identical
assert signal == extra_combo_signals[signal.name]
else:
extra_combo_signals[signal.name] = signal
self.push_struct(node.inst_name)
self.add_member("next", node.width)
self.add_member("load_next")
for signal in extra_combo_signals.values():
self.add_member(signal.name, signal.width)
self.pop_struct()
class FieldStorageStructGenerator(RDLStructGenerator):
def enter_Field(self, node: 'FieldNode') -> None:
if node.implements_storage:
self.add_member(node.inst_name, node.width)
class FieldLogicGenerator(RDLForLoopGenerator):
i_type = "genvar"
def __init__(self, field_builder: FieldBuilder):
super().__init__()
self.field_builder = field_builder
self.template = self.field_builder.exporter.jj_env.get_template(
"field_logic/templates/field_storage.sv"
)
def enter_Field(self, node: 'FieldNode') -> None:
# If a field doesn't implement storage, it is not relevant here
if not node.implements_storage:
return
conditionals = self.field_builder.get_conditionals(node)
extra_combo_signals = OrderedDict()
for conditional in conditionals:
for signal in conditional.get_extra_combo_signals(node):
extra_combo_signals[signal.name] = signal
reset_value = node.get_property("reset") or 0
sig = node.get_property("resetsignal")
if sig is not None:
resetsignal = RDLSignal(sig)
else:
resetsignal = self.field_builder.exporter.default_resetsignal
context = {
'node': node,
'reset': self.field_builder.exporter.dereferencer.get_value(reset_value),
'field_path': get_indexed_path(self.field_builder.top_node, node),
'extra_combo_signals': extra_combo_signals,
'conditionals': conditionals,
'resetsignal': resetsignal,
'get_always_ff_event': get_always_ff_event,
'has_value_output': self.field_builder.exporter.hwif.has_value_output,
'get_output_identifier': self.field_builder.exporter.hwif.get_output_identifier,
}
self.add_content(self.template.render(context))