177 lines
6.8 KiB
Python
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))
|