fill in more hwif utility functions for dereferencer
This commit is contained in:
@@ -1,105 +1,77 @@
|
||||
import re
|
||||
from typing import TYPE_CHECKING, List
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from systemrdl.node import AddrmapNode, FieldNode
|
||||
from systemrdl.rdltypes import PropertyReference
|
||||
|
||||
from ..utils import get_indexed_path
|
||||
from .field_builder import FieldBuilder, FieldStorageStructGenerator
|
||||
from .field_builder import CombinationalStructGenerator, FieldLogicGenerator
|
||||
|
||||
from systemrdl.node import Node, AddressableNode, RegNode, FieldNode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..exporter import RegblockExporter
|
||||
|
||||
class FieldLogic:
|
||||
def __init__(self, exporter:'RegblockExporter', top_node:Node):
|
||||
def __init__(self, exporter:'RegblockExporter'):
|
||||
self.exporter = exporter
|
||||
self.top_node = top_node
|
||||
self.field_builder = FieldBuilder(exporter)
|
||||
|
||||
self._indent_level = 0
|
||||
@property
|
||||
def top_node(self) -> AddrmapNode:
|
||||
return self.exporter.top_node
|
||||
|
||||
def get_storage_struct(self) -> str:
|
||||
lines = []
|
||||
self._do_struct(lines, self.top_node, is_top=True)
|
||||
struct_gen = FieldStorageStructGenerator()
|
||||
s = struct_gen.get_struct(self.top_node, "field_storage_t")
|
||||
|
||||
# Only declare the storage struct if it exists
|
||||
if lines:
|
||||
lines.append(f"{self._indent}field_storage_t field_storage;")
|
||||
return "\n".join(lines)
|
||||
if s is None:
|
||||
return ""
|
||||
|
||||
return s + "\nfield_storage_t field_storage;"
|
||||
|
||||
def get_combo_struct(self) -> str:
|
||||
struct_gen = CombinationalStructGenerator(self.field_builder)
|
||||
s = struct_gen.get_struct(self.top_node, "field_combo_t")
|
||||
|
||||
# Only declare the storage struct if it exists
|
||||
if s is None:
|
||||
return ""
|
||||
|
||||
return s + "\nfield_combo_t field_combo;"
|
||||
|
||||
def get_implementation(self) -> str:
|
||||
return "TODO:"
|
||||
gen = FieldLogicGenerator(self.field_builder)
|
||||
s = gen.get_content(self.top_node)
|
||||
if s is None:
|
||||
return ""
|
||||
return s
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Field utility functions
|
||||
#---------------------------------------------------------------------------
|
||||
def get_storage_identifier(self, node: FieldNode):
|
||||
def get_storage_identifier(self, node: FieldNode) -> str:
|
||||
"""
|
||||
Returns the Verilog string that represents the storage register element
|
||||
for the referenced field
|
||||
"""
|
||||
assert node.implements_storage
|
||||
|
||||
path = node.get_rel_path(self.top_node, empty_array_suffix="[!]")
|
||||
|
||||
# replace unknown indexes with incrementing iterators i0, i1, ...
|
||||
class repl:
|
||||
def __init__(self):
|
||||
self.i = 0
|
||||
def __call__(self, match):
|
||||
s = f'i{self.i}'
|
||||
self.i += 1
|
||||
return s
|
||||
path = re.sub(r'!', repl(), path)
|
||||
|
||||
path = get_indexed_path(self.top_node, node)
|
||||
return "field_storage." + path
|
||||
|
||||
def get_field_next_identifier(self, node: FieldNode) -> str:
|
||||
"""
|
||||
Returns a Verilog string that represents the field's next-state.
|
||||
This is specifically for use in Field->next property references.
|
||||
"""
|
||||
# TODO: Implement this
|
||||
raise NotImplementedError
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Struct generation functions
|
||||
#---------------------------------------------------------------------------
|
||||
@property
|
||||
def _indent(self) -> str:
|
||||
return " " * self._indent_level
|
||||
|
||||
def _get_node_array_suffix(self, node:AddressableNode) -> str:
|
||||
if node.is_array:
|
||||
return "".join([f'[{dim}]' for dim in node.array_dimensions])
|
||||
return ""
|
||||
|
||||
def _do_struct(self, lines:List[str], node:AddressableNode, is_top:bool = False) -> bool:
|
||||
# Collect struct members first
|
||||
contents = []
|
||||
self._indent_level += 1
|
||||
for child in node.children():
|
||||
if isinstance(child, RegNode):
|
||||
self._do_reg_struct(contents, child)
|
||||
elif isinstance(child, AddressableNode):
|
||||
self._do_struct(contents, child)
|
||||
self._indent_level -= 1
|
||||
|
||||
# If struct is not empty, emit a struct!
|
||||
if contents:
|
||||
if is_top:
|
||||
lines.append(f"{self._indent}typedef struct {{")
|
||||
else:
|
||||
lines.append(f"{self._indent}struct {{")
|
||||
|
||||
lines.extend(contents)
|
||||
|
||||
if is_top:
|
||||
lines.append(f"{self._indent}}} field_storage_t;")
|
||||
else:
|
||||
lines.append(f"{self._indent}}} {node.inst_name}{self._get_node_array_suffix(node)};")
|
||||
|
||||
|
||||
def _do_reg_struct(self, lines:List[str], node:RegNode) -> None:
|
||||
|
||||
fields = []
|
||||
for field in node.fields():
|
||||
if field.implements_storage:
|
||||
fields.append(field)
|
||||
|
||||
if not fields:
|
||||
return
|
||||
|
||||
lines.append(f"{self._indent}struct {{")
|
||||
self._indent_level += 1
|
||||
for field in fields:
|
||||
if field.width == 1:
|
||||
lines.append(f"{self._indent}logic {field.inst_name};")
|
||||
else:
|
||||
lines.append(f"{self._indent}logic [{field.width-1}:0] {field.inst_name};")
|
||||
self._indent_level -= 1
|
||||
lines.append(f"{self._indent}}} {node.inst_name}{self._get_node_array_suffix(node)};")
|
||||
def get_counter_control_identifier(self, prop_ref: PropertyReference) -> str:
|
||||
"""
|
||||
Return the Veriog string that represents the field's inferred incr/decr strobe signal.
|
||||
prop_ref will be either an incr or decr property reference, and it is already known that
|
||||
the incr/decr properties are not explicitly set by the user and are therefore inferred.
|
||||
"""
|
||||
# TODO: Implement this
|
||||
raise NotImplementedError
|
||||
|
||||
95
peakrdl/regblock/field_logic/bases.py
Normal file
95
peakrdl/regblock/field_logic/bases.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
import enum
|
||||
|
||||
from ..utils import get_indexed_path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import FieldNode
|
||||
|
||||
from ..exporter import RegblockExporter
|
||||
|
||||
class AssignmentPrecedence(enum.IntEnum):
|
||||
"""
|
||||
Enumeration of standard assignment precedence groups.
|
||||
Each value represents the precedence of a single conditional assignment
|
||||
category that determines a field's next state.
|
||||
|
||||
Higher value denotes higher precedence
|
||||
|
||||
Important: If inserting custom intermediate assignment rules, do not rely on the absolute
|
||||
value of the enumeration. Insert your rules relative to an existing precedence:
|
||||
FieldBuilder.add_hw_conditional(MyConditional, HW_WE + 1)
|
||||
"""
|
||||
|
||||
# Software access assignment groups
|
||||
SW_ONREAD = 5000
|
||||
SW_ONWRITE = 4000
|
||||
|
||||
# Hardware access assignment groups
|
||||
HW_WE = 3000
|
||||
HWSET = 2000
|
||||
HWCLR = 1000
|
||||
COUNTER_INCR_DECR = 0
|
||||
|
||||
|
||||
|
||||
|
||||
class SVLogic:
|
||||
"""
|
||||
Represents a SystemVerilog logic signal
|
||||
"""
|
||||
def __init__(self, name: str, width: int, default_assignment: str) -> None:
|
||||
self.name = name
|
||||
self.width = width
|
||||
self.default_assignment = default_assignment
|
||||
|
||||
def __eq__(self, o: object) -> bool:
|
||||
if not isinstance(o, SVLogic):
|
||||
return False
|
||||
|
||||
return (
|
||||
o.name == self.name
|
||||
and o.width == self.width
|
||||
and o.default_assignment == self.default_assignment
|
||||
)
|
||||
|
||||
|
||||
class NextStateConditional:
|
||||
"""
|
||||
Decribes a single conditional action that determines the next state of a field
|
||||
Provides information to generate the following content:
|
||||
if(<conditional>) begin
|
||||
<assignments>
|
||||
end
|
||||
"""
|
||||
def __init__(self, exporter:'RegblockExporter'):
|
||||
self.exporter = exporter
|
||||
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
"""
|
||||
Returns True if this conditional is relevant to the field. If so,
|
||||
it instructs the FieldBuider that Verilog for this conditional shall
|
||||
be emitted
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_field_path(self, field:'FieldNode') -> str:
|
||||
return get_indexed_path(self.exporter.top_node, field)
|
||||
|
||||
def get_conditional(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Returns the rendered conditional text
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
"""
|
||||
Returns a list of rendered assignment strings
|
||||
This will basically always be two:
|
||||
<field>.next = <next value>
|
||||
<field>.load_next = '1;
|
||||
"""
|
||||
|
||||
def get_extra_combo_signals(self, field: 'FieldNode') -> List[SVLogic]:
|
||||
return []
|
||||
176
peakrdl/regblock/field_logic/field_builder.py
Normal file
176
peakrdl/regblock/field_logic/field_builder.py
Normal file
@@ -0,0 +1,176 @@
|
||||
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))
|
||||
38
peakrdl/regblock/field_logic/sw_onread.py
Normal file
38
peakrdl/regblock/field_logic/sw_onread.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from systemrdl.rdltypes import OnReadType
|
||||
|
||||
from .bases import NextStateConditional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import FieldNode
|
||||
|
||||
class _OnRead(NextStateConditional):
|
||||
onreadtype = None
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return field.get_property("onread") == self.onreadtype
|
||||
|
||||
def get_conditional(self, field: 'FieldNode') -> str:
|
||||
strb = self.exporter.dereferencer.get_access_strobe(field)
|
||||
return f"decoded_req && !decoded_req_is_wr && {strb}"
|
||||
|
||||
class ClearOnRead(_OnRead):
|
||||
onreadtype = OnReadType.rclr
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '0;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
|
||||
class SetOnRead(_OnRead):
|
||||
onreadtype = OnReadType.rset
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '1;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
107
peakrdl/regblock/field_logic/sw_onwrite.py
Normal file
107
peakrdl/regblock/field_logic/sw_onwrite.py
Normal file
@@ -0,0 +1,107 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from systemrdl.rdltypes import OnWriteType
|
||||
|
||||
from .bases import NextStateConditional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import FieldNode
|
||||
|
||||
class _OnWrite(NextStateConditional):
|
||||
onwritetype = None
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return field.get_property("onwrite") == self.onwritetype
|
||||
|
||||
def get_conditional(self, field: 'FieldNode') -> str:
|
||||
strb = self.exporter.dereferencer.get_access_strobe(field)
|
||||
return f"decoded_req && decoded_req_is_wr && {strb}"
|
||||
|
||||
class WriteOneSet(_OnWrite):
|
||||
onwritetype = OnWriteType.woset
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} | decoded_wr_data;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
class WriteOneClear(_OnWrite):
|
||||
onwritetype = OnWriteType.woclr
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} & ~decoded_wr_data;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
class WriteOneToggle(_OnWrite):
|
||||
onwritetype = OnWriteType.wot
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} ^ decoded_wr_data;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroSet(_OnWrite):
|
||||
onwritetype = OnWriteType.wzs
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} | ~decoded_wr_data;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroClear(_OnWrite):
|
||||
onwritetype = OnWriteType.wzc
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} & decoded_wr_data;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroToggle(_OnWrite):
|
||||
onwritetype = OnWriteType.wzt
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} ^ ~decoded_wr_data;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
class WriteClear(_OnWrite):
|
||||
onwritetype = OnWriteType.wclr
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '0;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
class WriteSet(_OnWrite):
|
||||
onwritetype = OnWriteType.wset
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '1;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
|
||||
class Write(_OnWrite):
|
||||
onwritetype = None
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = decoded_wr_data;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
]
|
||||
25
peakrdl/regblock/field_logic/templates/field_storage.sv
Normal file
25
peakrdl/regblock/field_logic/templates/field_storage.sv
Normal file
@@ -0,0 +1,25 @@
|
||||
// Field: {{node.get_path()}}
|
||||
always_comb begin
|
||||
field_combo.{{field_path}}.next = '0;
|
||||
field_combo.{{field_path}}.load_next = '0;
|
||||
{%- for signal in extra_combo_signals %}
|
||||
field_combo.{{field_path}}.{{signal.name}} = {{signal.default_assignment}};
|
||||
{%- endfor %}
|
||||
{%- for conditional in conditionals %}
|
||||
{% if not loop.first %}end else {% endif %}if({{conditional.get_conditional(node)}}) begin
|
||||
{%- for assignment in conditional.get_assignments(node) %}
|
||||
{{assignment|indent}}
|
||||
{%- endfor %}
|
||||
end
|
||||
{%- endfor %}
|
||||
end
|
||||
always_ff {{get_always_ff_event(resetsignal)}} begin
|
||||
if({{resetsignal.activehigh_identifier}}) begin
|
||||
field_storage.{{field_path}} <= {{reset}};
|
||||
end else if(field_combo.{{field_path}}.load_next) begin
|
||||
field_storage.{{field_path}} <= field_combo.{{field_path}}.next;
|
||||
end
|
||||
end
|
||||
{% if has_value_output(node) -%}
|
||||
assign {{get_output_identifier(node)}} = field_storage.{{field_path}};
|
||||
{%- endif -%}
|
||||
Reference in New Issue
Block a user