Switch to use regular non-namespaced package
This commit is contained in:
330
src/peakrdl_regblock/field_logic/__init__.py
Normal file
330
src/peakrdl_regblock/field_logic/__init__.py
Normal file
@@ -0,0 +1,330 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from systemrdl.rdltypes import PropertyReference, PrecedenceType, InterruptType
|
||||
from systemrdl.node import Node
|
||||
|
||||
from .bases import AssignmentPrecedence, NextStateConditional
|
||||
from . import sw_onread
|
||||
from . import sw_onwrite
|
||||
from . import sw_singlepulse
|
||||
from . import hw_write
|
||||
from . import hw_set_clr
|
||||
from . import hw_interrupts
|
||||
|
||||
from ..utils import get_indexed_path
|
||||
|
||||
from .generators import CombinationalStructGenerator, FieldStorageStructGenerator, FieldLogicGenerator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Dict, List
|
||||
from systemrdl.node import AddrmapNode, FieldNode
|
||||
from ..exporter import RegblockExporter
|
||||
|
||||
class FieldLogic:
|
||||
def __init__(self, exp:'RegblockExporter'):
|
||||
self.exp = exp
|
||||
|
||||
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.exp.top_node
|
||||
|
||||
def get_storage_struct(self) -> str:
|
||||
struct_gen = FieldStorageStructGenerator(self)
|
||||
s = struct_gen.get_struct(self.top_node, "field_storage_t")
|
||||
|
||||
# Only declare the storage struct if it exists
|
||||
if s is None:
|
||||
return ""
|
||||
|
||||
return s + "\nfield_storage_t field_storage;"
|
||||
|
||||
def get_combo_struct(self) -> str:
|
||||
struct_gen = CombinationalStructGenerator(self)
|
||||
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:
|
||||
gen = FieldLogicGenerator(self)
|
||||
s = gen.get_content(self.top_node)
|
||||
if s is None:
|
||||
return ""
|
||||
return s
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Field utility functions
|
||||
#---------------------------------------------------------------------------
|
||||
def get_storage_identifier(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Returns the Verilog string that represents the storage register element
|
||||
for the referenced field
|
||||
"""
|
||||
assert field.implements_storage
|
||||
path = get_indexed_path(self.top_node, field)
|
||||
return f"field_storage.{path}.value"
|
||||
|
||||
def get_next_q_identifier(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Returns the Verilog string that represents the storage register element
|
||||
for the delayed 'next' input value
|
||||
"""
|
||||
assert field.implements_storage
|
||||
path = get_indexed_path(self.top_node, field)
|
||||
return f"field_storage.{path}.next_q"
|
||||
|
||||
def get_field_combo_identifier(self, field: 'FieldNode', name: str) -> str:
|
||||
"""
|
||||
Returns a Verilog string that represents a field's internal combinational
|
||||
signal.
|
||||
"""
|
||||
assert field.implements_storage
|
||||
path = get_indexed_path(self.top_node, field)
|
||||
return f"field_combo.{path}.{name}"
|
||||
|
||||
def get_counter_incr_strobe(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Return the Verilog string that represents the field's incr strobe signal.
|
||||
"""
|
||||
prop_value = field.get_property('incr')
|
||||
if prop_value:
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
# unset by the user, points to the implied input signal
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "incr")
|
||||
|
||||
def get_counter_incrvalue(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Return the string that represents the field's increment value
|
||||
"""
|
||||
incrvalue = field.get_property('incrvalue')
|
||||
if incrvalue is not None:
|
||||
return self.exp.dereferencer.get_value(incrvalue)
|
||||
if field.get_property('incrwidth'):
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "incrvalue")
|
||||
return "1'b1"
|
||||
|
||||
def get_counter_incrsaturate_value(self, field: 'FieldNode') -> str:
|
||||
prop_value = field.get_property('incrsaturate')
|
||||
if prop_value is True:
|
||||
return self.exp.dereferencer.get_value(2**field.width - 1)
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def counter_incrsaturates(self, field: 'FieldNode') -> bool:
|
||||
"""
|
||||
Returns True if the counter saturates
|
||||
"""
|
||||
return field.get_property('incrsaturate') is not False
|
||||
|
||||
def get_counter_incrthreshold_value(self, field: 'FieldNode') -> str:
|
||||
prop_value = field.get_property('incrthreshold')
|
||||
if isinstance(prop_value, bool):
|
||||
# No explicit value set. use max
|
||||
return self.exp.dereferencer.get_value(2**field.width - 1)
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def get_counter_decr_strobe(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Return the Verilog string that represents the field's incr strobe signal.
|
||||
"""
|
||||
prop_value = field.get_property('decr')
|
||||
if prop_value:
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
# unset by the user, points to the implied input signal
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "decr")
|
||||
|
||||
def get_counter_decrvalue(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Return the string that represents the field's decrement value
|
||||
"""
|
||||
decrvalue = field.get_property('decrvalue')
|
||||
if decrvalue is not None:
|
||||
return self.exp.dereferencer.get_value(decrvalue)
|
||||
if field.get_property('decrwidth'):
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "decrvalue")
|
||||
return "1'b1"
|
||||
|
||||
def get_counter_decrsaturate_value(self, field: 'FieldNode') -> str:
|
||||
prop_value = field.get_property('decrsaturate')
|
||||
if prop_value is True:
|
||||
return "'d0"
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def counter_decrsaturates(self, field: 'FieldNode') -> bool:
|
||||
"""
|
||||
Returns True if the counter saturates
|
||||
"""
|
||||
return field.get_property('decrsaturate') is not False
|
||||
|
||||
def get_counter_decrthreshold_value(self, field: 'FieldNode') -> str:
|
||||
prop_value = field.get_property('decrthreshold')
|
||||
if isinstance(prop_value, bool):
|
||||
# No explicit value set. use min
|
||||
return "'d0"
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def get_swacc_identifier(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Asserted when field is software accessed (read)
|
||||
"""
|
||||
strb = self.exp.dereferencer.get_access_strobe(field)
|
||||
return f"{strb} && !decoded_req_is_wr"
|
||||
|
||||
def get_swmod_identifier(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Asserted when field is modified by software (written or read with a
|
||||
set or clear side effect).
|
||||
"""
|
||||
w_modifiable = field.is_sw_writable
|
||||
r_modifiable = (field.get_property('onread') is not None)
|
||||
strb = self.exp.dereferencer.get_access_strobe(field)
|
||||
|
||||
if w_modifiable and not r_modifiable:
|
||||
# assert swmod only on sw write
|
||||
return f"{strb} && decoded_req_is_wr"
|
||||
|
||||
if w_modifiable and r_modifiable:
|
||||
# assert swmod on all sw actions
|
||||
return strb
|
||||
|
||||
if not w_modifiable and r_modifiable:
|
||||
# assert swmod only on sw read
|
||||
return f"{strb} && !decoded_req_is_wr"
|
||||
|
||||
# Not sw modifiable
|
||||
return "1'b0"
|
||||
|
||||
|
||||
def has_next_q(self, field: 'FieldNode') -> bool:
|
||||
"""
|
||||
Some fields require a delayed version of their 'next' input signal in
|
||||
order to do edge-detection.
|
||||
|
||||
Returns True if this is the case.
|
||||
"""
|
||||
if field.get_property('intr type') in {
|
||||
InterruptType.posedge,
|
||||
InterruptType.negedge,
|
||||
InterruptType.bothedge
|
||||
}:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Field Logic Conditionals
|
||||
#---------------------------------------------------------------------------
|
||||
def add_hw_conditional(self, conditional: NextStateConditional, precedence: AssignmentPrecedence) -> None:
|
||||
"""
|
||||
Register a NextStateConditional action for hardware-triggered field updates.
|
||||
Categorizing conditionals correctly by hw/sw ensures that the RDL precedence
|
||||
property can be reliably honored.
|
||||
|
||||
The ``precedence`` argument determines the conditional assignment's priority over
|
||||
other assignments of differing precedence.
|
||||
|
||||
If multiple conditionals of the same precedence are registered, they are
|
||||
searched sequentially and only the first to match the given field is used.
|
||||
"""
|
||||
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:
|
||||
"""
|
||||
Register a NextStateConditional action for software-triggered field updates.
|
||||
Categorizing conditionals correctly by hw/sw ensures that the RDL precedence
|
||||
property can be reliably honored.
|
||||
|
||||
The ``precedence`` argument determines the conditional assignment's priority over
|
||||
other assignments of differing precedence.
|
||||
|
||||
If multiple conditionals of the same precedence are registered, they are
|
||||
searched sequentially and only the first to match the given field is used.
|
||||
"""
|
||||
if precedence not in self._sw_conditionals:
|
||||
self._sw_conditionals[precedence] = []
|
||||
self._sw_conditionals[precedence].append(conditional)
|
||||
|
||||
|
||||
def init_conditionals(self) -> None:
|
||||
"""
|
||||
Initialize all possible conditionals here.
|
||||
|
||||
Remember: The order in which conditionals are added matters within the
|
||||
same assignment precedence.
|
||||
"""
|
||||
|
||||
self.add_sw_conditional(sw_onread.ClearOnRead(self.exp), AssignmentPrecedence.SW_ONREAD)
|
||||
self.add_sw_conditional(sw_onread.SetOnRead(self.exp), AssignmentPrecedence.SW_ONREAD)
|
||||
|
||||
self.add_sw_conditional(sw_onwrite.Write(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroToggle(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneToggle(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
|
||||
self.add_sw_conditional(sw_singlepulse.Singlepulse(self.exp), AssignmentPrecedence.SW_SINGLEPULSE)
|
||||
|
||||
self.add_hw_conditional(hw_interrupts.PosedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.NegedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.BothedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.PosedgeNonsticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.NegedgeNonsticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.BothedgeNonsticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.Sticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.Stickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_write.WEWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_write.WELWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_write.AlwaysWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
|
||||
self.add_hw_conditional(hw_set_clr.HWClear(self.exp), AssignmentPrecedence.HWCLR)
|
||||
|
||||
self.add_hw_conditional(hw_set_clr.HWSet(self.exp), AssignmentPrecedence.HWSET)
|
||||
|
||||
|
||||
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)
|
||||
break
|
||||
return result
|
||||
|
||||
|
||||
def get_conditionals(self, field: 'FieldNode') -> 'List[NextStateConditional]':
|
||||
"""
|
||||
Get a list of NextStateConditional objects that apply to the given field.
|
||||
|
||||
The returned list is sorted in priority order - the conditional with highest
|
||||
precedence is first in the list.
|
||||
"""
|
||||
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
|
||||
102
src/peakrdl_regblock/field_logic/bases.py
Normal file
102
src/peakrdl_regblock/field_logic/bases.py
Normal file
@@ -0,0 +1,102 @@
|
||||
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
|
||||
SW_SINGLEPULSE = 3000
|
||||
|
||||
# Hardware access assignment groups
|
||||
HW_WRITE = 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
|
||||
"""
|
||||
|
||||
comment = ""
|
||||
def __init__(self, exp:'RegblockExporter'):
|
||||
self.exp = exp
|
||||
|
||||
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.exp.top_node, field)
|
||||
|
||||
def get_predicate(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 any additional combinational signals that this conditional
|
||||
will assign if present.
|
||||
"""
|
||||
return []
|
||||
264
src/peakrdl_regblock/field_logic/generators.py
Normal file
264
src/peakrdl_regblock/field_logic/generators.py
Normal file
@@ -0,0 +1,264 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from ..struct_generator import RDLStructGenerator
|
||||
from ..forloop_generator import RDLForLoopGenerator
|
||||
from ..utils import get_always_ff_event
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import FieldLogic
|
||||
from systemrdl.node import FieldNode, RegNode
|
||||
from .bases import SVLogic
|
||||
|
||||
class CombinationalStructGenerator(RDLStructGenerator):
|
||||
|
||||
def __init__(self, field_logic: 'FieldLogic'):
|
||||
super().__init__()
|
||||
self.field_logic = field_logic
|
||||
|
||||
|
||||
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() # type: OrderedDict[str, SVLogic]
|
||||
for conditional in self.field_logic.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)
|
||||
if node.is_up_counter:
|
||||
self.add_up_counter_members(node)
|
||||
if node.is_down_counter:
|
||||
self.add_down_counter_members(node)
|
||||
self.pop_struct()
|
||||
|
||||
def add_up_counter_members(self, node: 'FieldNode') -> None:
|
||||
self.add_member('incrthreshold')
|
||||
if self.field_logic.counter_incrsaturates(node):
|
||||
self.add_member('incrsaturate')
|
||||
else:
|
||||
self.add_member('overflow')
|
||||
|
||||
def add_down_counter_members(self, node: 'FieldNode') -> None:
|
||||
self.add_member('decrthreshold')
|
||||
if self.field_logic.counter_decrsaturates(node):
|
||||
self.add_member('decrsaturate')
|
||||
else:
|
||||
self.add_member('underflow')
|
||||
|
||||
|
||||
class FieldStorageStructGenerator(RDLStructGenerator):
|
||||
|
||||
def __init__(self, field_logic: 'FieldLogic') -> None:
|
||||
super().__init__()
|
||||
self.field_logic = field_logic
|
||||
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
self.push_struct(node.inst_name)
|
||||
|
||||
if node.implements_storage:
|
||||
self.add_member("value", node.width)
|
||||
|
||||
if self.field_logic.has_next_q(node):
|
||||
self.add_member("next_q", node.width)
|
||||
|
||||
self.pop_struct()
|
||||
|
||||
|
||||
class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
i_type = "genvar"
|
||||
def __init__(self, field_logic: 'FieldLogic') -> None:
|
||||
super().__init__()
|
||||
self.field_logic = field_logic
|
||||
self.exp = field_logic.exp
|
||||
self.field_storage_template = self.field_logic.exp.jj_env.get_template(
|
||||
"field_logic/templates/field_storage.sv"
|
||||
)
|
||||
self.intr_fields = [] # type: List[FieldNode]
|
||||
self.halt_fields = [] # type: List[FieldNode]
|
||||
|
||||
|
||||
def enter_Reg(self, node: 'RegNode') -> None:
|
||||
self.intr_fields = []
|
||||
self.halt_fields = []
|
||||
|
||||
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
if node.implements_storage:
|
||||
self.generate_field_storage(node)
|
||||
|
||||
self.assign_field_outputs(node)
|
||||
|
||||
if node.get_property('intr'):
|
||||
self.intr_fields.append(node)
|
||||
if node.get_property('haltenable') or node.get_property('haltmask'):
|
||||
self.halt_fields.append(node)
|
||||
|
||||
|
||||
def exit_Reg(self, node: 'RegNode') -> None:
|
||||
# Assign register's intr output
|
||||
if self.intr_fields:
|
||||
strs = []
|
||||
for field in self.intr_fields:
|
||||
enable = field.get_property('enable')
|
||||
mask = field.get_property('mask')
|
||||
F = self.exp.dereferencer.get_value(field)
|
||||
if enable:
|
||||
E = self.exp.dereferencer.get_value(enable)
|
||||
s = f"|({F} & {E})"
|
||||
elif mask:
|
||||
M = self.exp.dereferencer.get_value(mask)
|
||||
s = f"|({F} & ~{M})"
|
||||
else:
|
||||
s = f"|{F}"
|
||||
strs.append(s)
|
||||
|
||||
self.add_content(
|
||||
f"assign {self.exp.hwif.get_implied_prop_output_identifier(node, 'intr')} ="
|
||||
)
|
||||
self.add_content(
|
||||
" "
|
||||
+ "\n || ".join(strs)
|
||||
+ ";"
|
||||
)
|
||||
|
||||
# Assign register's halt output
|
||||
if self.halt_fields:
|
||||
strs = []
|
||||
for field in self.halt_fields:
|
||||
enable = field.get_property('haltenable')
|
||||
mask = field.get_property('haltmask')
|
||||
F = self.exp.dereferencer.get_value(field)
|
||||
if enable:
|
||||
E = self.exp.dereferencer.get_value(enable)
|
||||
s = f"|({F} & {E})"
|
||||
elif mask:
|
||||
M = self.exp.dereferencer.get_value(mask)
|
||||
s = f"|({F} & ~{M})"
|
||||
else:
|
||||
s = f"|{F}"
|
||||
strs.append(s)
|
||||
|
||||
self.add_content(
|
||||
f"assign {self.exp.hwif.get_implied_prop_output_identifier(node, 'halt')} ="
|
||||
)
|
||||
self.add_content(
|
||||
" "
|
||||
+ "\n || ".join(strs)
|
||||
+ ";"
|
||||
)
|
||||
|
||||
|
||||
def generate_field_storage(self, node: 'FieldNode') -> None:
|
||||
conditionals = self.field_logic.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
|
||||
|
||||
resetsignal = node.get_property('resetsignal')
|
||||
|
||||
reset_value = node.get_property('reset')
|
||||
if reset_value is not None:
|
||||
reset_value_str = self.exp.dereferencer.get_value(reset_value)
|
||||
else:
|
||||
# 5.9.1-g: If no reset value given, the field is not reset, even if it has a resetsignal.
|
||||
reset_value_str = None
|
||||
resetsignal = None
|
||||
|
||||
context = {
|
||||
'node': node,
|
||||
'reset': reset_value_str,
|
||||
'field_logic': self.field_logic,
|
||||
'extra_combo_signals': extra_combo_signals,
|
||||
'conditionals': conditionals,
|
||||
'resetsignal': resetsignal,
|
||||
'get_always_ff_event': lambda resetsignal : get_always_ff_event(self.exp.dereferencer, resetsignal),
|
||||
'get_value': self.exp.dereferencer.get_value,
|
||||
'get_resetsignal': self.exp.dereferencer.get_resetsignal,
|
||||
'get_input_identifier': self.exp.hwif.get_input_identifier,
|
||||
}
|
||||
self.add_content(self.field_storage_template.render(context))
|
||||
|
||||
|
||||
def assign_field_outputs(self, node: 'FieldNode') -> None:
|
||||
# Field value output
|
||||
if self.exp.hwif.has_value_output(node):
|
||||
output_identifier = self.exp.hwif.get_output_identifier(node)
|
||||
value = self.exp.dereferencer.get_value(node)
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
|
||||
# Inferred logical reduction outputs
|
||||
if node.get_property('anded'):
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "anded")
|
||||
value = self.exp.dereferencer.get_field_propref_value(node, "anded")
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
if node.get_property('ored'):
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "ored")
|
||||
value = self.exp.dereferencer.get_field_propref_value(node, "ored")
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
if node.get_property('xored'):
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "xored")
|
||||
value = self.exp.dereferencer.get_field_propref_value(node, "xored")
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
|
||||
if node.get_property('swmod'):
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "swmod")
|
||||
value = self.field_logic.get_swmod_identifier(node)
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
|
||||
if node.get_property('swacc'):
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "swacc")
|
||||
value = self.field_logic.get_swacc_identifier(node)
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
|
||||
if node.get_property('incrthreshold') is not False: # (explicitly not False. Not 0)
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "incrthreshold")
|
||||
value = self.field_logic.get_field_combo_identifier(node, 'incrthreshold')
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
if node.get_property('decrthreshold') is not False: # (explicitly not False. Not 0)
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "decrthreshold")
|
||||
value = self.field_logic.get_field_combo_identifier(node, 'decrthreshold')
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
|
||||
if node.get_property('overflow'):
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "overflow")
|
||||
value = self.field_logic.get_field_combo_identifier(node, 'overflow')
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
if node.get_property('underflow'):
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "underflow")
|
||||
value = self.field_logic.get_field_combo_identifier(node, 'underflow')
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
202
src/peakrdl_regblock/field_logic/hw_interrupts.py
Normal file
202
src/peakrdl_regblock/field_logic/hw_interrupts.py
Normal file
@@ -0,0 +1,202 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from systemrdl.rdltypes import InterruptType
|
||||
|
||||
from .bases import NextStateConditional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import FieldNode
|
||||
|
||||
|
||||
class Sticky(NextStateConditional):
|
||||
"""
|
||||
Normal multi-bit sticky
|
||||
"""
|
||||
comment = "multi-bit sticky"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and field.get_property('sticky')
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return f"({R} == '0) && ({I} != '0)"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
return [
|
||||
f"next_c = {I};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
|
||||
class Stickybit(NextStateConditional):
|
||||
"""
|
||||
Normal stickybit
|
||||
"""
|
||||
comment = "stickybit"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and field.get_property('stickybit')
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
return self.exp.hwif.get_input_identifier(field)
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} | {I};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class PosedgeStickybit(NextStateConditional):
|
||||
"""
|
||||
Positive edge stickybit
|
||||
"""
|
||||
comment = "posedge stickybit"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and field.get_property('stickybit')
|
||||
and field.get_property('intr type') == InterruptType.posedge
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
return f"~{Iq} & {I}"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} | (~{Iq} & {I});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class NegedgeStickybit(NextStateConditional):
|
||||
"""
|
||||
Negative edge stickybit
|
||||
"""
|
||||
comment = "negedge stickybit"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and field.get_property('stickybit')
|
||||
and field.get_property('intr type') == InterruptType.negedge
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
return f"{Iq} & ~{I}"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} | ({Iq} & ~{I});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class BothedgeStickybit(NextStateConditional):
|
||||
"""
|
||||
edge-sensitive stickybit
|
||||
"""
|
||||
comment = "bothedge stickybit"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and field.get_property('stickybit')
|
||||
and field.get_property('intr type') == InterruptType.bothedge
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
return f"{Iq} ^ {I}"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} | ({Iq} ^ {I});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class PosedgeNonsticky(NextStateConditional):
|
||||
"""
|
||||
Positive edge non-stickybit
|
||||
"""
|
||||
comment = "posedge nonsticky"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and not field.get_property('stickybit')
|
||||
and field.get_property('intr type') == InterruptType.posedge
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
return "1"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
return [
|
||||
f"next_c = ~{Iq} & {I};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class NegedgeNonsticky(NextStateConditional):
|
||||
"""
|
||||
Negative edge non-stickybit
|
||||
"""
|
||||
comment = "negedge nonsticky"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and not field.get_property('stickybit')
|
||||
and field.get_property('intr type') == InterruptType.negedge
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
return "1"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
return [
|
||||
f"next_c = {Iq} & ~{I};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class BothedgeNonsticky(NextStateConditional):
|
||||
"""
|
||||
edge-sensitive non-stickybit
|
||||
"""
|
||||
comment = "bothedge nonsticky"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and not field.get_property('stickybit')
|
||||
and field.get_property('intr type') == InterruptType.bothedge
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
return "1"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
Iq = self.exp.field_logic.get_next_q_identifier(field)
|
||||
return [
|
||||
f"next_c = {Iq} ^ {I};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
72
src/peakrdl_regblock/field_logic/hw_set_clr.py
Normal file
72
src/peakrdl_regblock/field_logic/hw_set_clr.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from .bases import NextStateConditional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import FieldNode
|
||||
|
||||
|
||||
class HWSet(NextStateConditional):
|
||||
comment = "HW Set"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return bool(field.get_property('hwset'))
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
prop = field.get_property('hwset')
|
||||
if isinstance(prop, bool):
|
||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "hwset")
|
||||
else:
|
||||
# signal or field
|
||||
identifier = self.exp.dereferencer.get_value(prop)
|
||||
return identifier
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
hwmask = field.get_property('hwmask')
|
||||
hwenable = field.get_property('hwenable')
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
if hwmask is not None:
|
||||
M = self.exp.dereferencer.get_value(hwmask)
|
||||
next_val = f"{R} | ~{M}"
|
||||
elif hwenable is not None:
|
||||
E = self.exp.dereferencer.get_value(hwenable)
|
||||
next_val = f"{R} | {E}"
|
||||
else:
|
||||
next_val = "'1"
|
||||
|
||||
return [
|
||||
f"next_c = {next_val};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
|
||||
class HWClear(NextStateConditional):
|
||||
comment = "HW Clear"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return bool(field.get_property('hwclr'))
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
prop = field.get_property('hwclr')
|
||||
if isinstance(prop, bool):
|
||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "hwclr")
|
||||
else:
|
||||
# signal or field
|
||||
identifier = self.exp.dereferencer.get_value(prop)
|
||||
return identifier
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
hwmask = field.get_property('hwmask')
|
||||
hwenable = field.get_property('hwenable')
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
if hwmask is not None:
|
||||
M = self.exp.dereferencer.get_value(hwmask)
|
||||
next_val = f"{R} & {M}"
|
||||
elif hwenable is not None:
|
||||
E = self.exp.dereferencer.get_value(hwenable)
|
||||
next_val = f"{R} & ~{E}"
|
||||
else:
|
||||
next_val = "'0"
|
||||
|
||||
return [
|
||||
f"next_c = {next_val};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
76
src/peakrdl_regblock/field_logic/hw_write.py
Normal file
76
src/peakrdl_regblock/field_logic/hw_write.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from .bases import NextStateConditional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import FieldNode
|
||||
|
||||
|
||||
class AlwaysWrite(NextStateConditional):
|
||||
"""
|
||||
hw writable, without any qualifying we/wel
|
||||
"""
|
||||
comment = "HW Write"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and not field.get_property('we')
|
||||
and not field.get_property('wel')
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
# TODO: make exporter promote this to an "else"?
|
||||
return "1"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
hwmask = field.get_property('hwmask')
|
||||
hwenable = field.get_property('hwenable')
|
||||
I = self.exp.hwif.get_input_identifier(field)
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
if hwmask is not None:
|
||||
M = self.exp.dereferencer.get_value(hwmask)
|
||||
next_val = f"{I} & ~{M} | {R} & {M}"
|
||||
elif hwenable is not None:
|
||||
E = self.exp.dereferencer.get_value(hwenable)
|
||||
next_val = f"{I} & {E} | {R} & ~{E}"
|
||||
else:
|
||||
next_val = I
|
||||
|
||||
return [
|
||||
f"next_c = {next_val};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WEWrite(AlwaysWrite):
|
||||
comment = "HW Write - we"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and field.get_property('we')
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
prop = field.get_property('we')
|
||||
if isinstance(prop, bool):
|
||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "we")
|
||||
else:
|
||||
# signal or field
|
||||
identifier = self.exp.dereferencer.get_value(prop)
|
||||
return identifier
|
||||
|
||||
class WELWrite(AlwaysWrite):
|
||||
comment = "HW Write - wel"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return (
|
||||
field.is_hw_writable
|
||||
and field.get_property('wel')
|
||||
)
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
prop = field.get_property('wel')
|
||||
if isinstance(prop, bool):
|
||||
identifier = self.exp.hwif.get_implied_prop_input_identifier(field, "wel")
|
||||
else:
|
||||
# signal or field
|
||||
identifier = self.exp.dereferencer.get_value(prop)
|
||||
return f"!{identifier}"
|
||||
39
src/peakrdl_regblock/field_logic/sw_onread.py
Normal file
39
src/peakrdl_regblock/field_logic/sw_onread.py
Normal file
@@ -0,0 +1,39 @@
|
||||
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_predicate(self, field: 'FieldNode') -> str:
|
||||
strb = self.exp.dereferencer.get_access_strobe(field)
|
||||
return f"{strb} && !decoded_req_is_wr"
|
||||
|
||||
|
||||
class ClearOnRead(_OnRead):
|
||||
comment = "SW clear on read"
|
||||
onreadtype = OnReadType.rclr
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
return [
|
||||
"next_c = '0;",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
|
||||
class SetOnRead(_OnRead):
|
||||
comment = "SW set on read"
|
||||
onreadtype = OnReadType.rset
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
return [
|
||||
"next_c = '1;",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
130
src/peakrdl_regblock/field_logic/sw_onwrite.py
Normal file
130
src/peakrdl_regblock/field_logic/sw_onwrite.py
Normal file
@@ -0,0 +1,130 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from systemrdl.rdltypes import OnWriteType
|
||||
|
||||
from .bases import NextStateConditional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import FieldNode
|
||||
|
||||
# TODO: implement sw=w1 "write once" fields
|
||||
|
||||
class _OnWrite(NextStateConditional):
|
||||
onwritetype = None
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return field.is_sw_writable and field.get_property('onwrite') == self.onwritetype
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
strb = self.exp.dereferencer.get_access_strobe(field)
|
||||
|
||||
if field.get_property('swwe') or field.get_property('swwel'):
|
||||
# dereferencer will wrap swwel complement if necessary
|
||||
qualifier = self.exp.dereferencer.get_field_propref_value(field, 'swwe')
|
||||
return f"{strb} && decoded_req_is_wr && {qualifier}"
|
||||
|
||||
return f"{strb} && decoded_req_is_wr"
|
||||
|
||||
|
||||
def _wr_data(self, field: 'FieldNode') -> str:
|
||||
if field.msb < field.lsb:
|
||||
# Field gets bitswapped since it is in [low:high] orientation
|
||||
value = f"{{<<{{decoded_wr_data[{field.high}:{field.low}]}}}}"
|
||||
else:
|
||||
value = f"decoded_wr_data[{field.high}:{field.low}]"
|
||||
return value
|
||||
|
||||
class WriteOneSet(_OnWrite):
|
||||
comment = "SW write 1 set"
|
||||
onwritetype = OnWriteType.woset
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} | {self._wr_data(field)};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteOneClear(_OnWrite):
|
||||
comment = "SW write 1 clear"
|
||||
onwritetype = OnWriteType.woclr
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} & ~{self._wr_data(field)};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteOneToggle(_OnWrite):
|
||||
comment = "SW write 1 toggle"
|
||||
onwritetype = OnWriteType.wot
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} ^ {self._wr_data(field)};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroSet(_OnWrite):
|
||||
comment = "SW write 0 set"
|
||||
onwritetype = OnWriteType.wzs
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} | ~{self._wr_data(field)};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroClear(_OnWrite):
|
||||
comment = "SW write 0 clear"
|
||||
onwritetype = OnWriteType.wzc
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} & {self._wr_data(field)};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroToggle(_OnWrite):
|
||||
comment = "SW write 0 toggle"
|
||||
onwritetype = OnWriteType.wzt
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
return [
|
||||
f"next_c = {R} ^ ~{self._wr_data(field)};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteClear(_OnWrite):
|
||||
comment = "SW write clear"
|
||||
onwritetype = OnWriteType.wclr
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
return [
|
||||
"next_c = '0;",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteSet(_OnWrite):
|
||||
comment = "SW write set"
|
||||
onwritetype = OnWriteType.wset
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
return [
|
||||
"next_c = '1;",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class Write(_OnWrite):
|
||||
comment = "SW write"
|
||||
onwritetype = None
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
return [
|
||||
f"next_c = {self._wr_data(field)};",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
22
src/peakrdl_regblock/field_logic/sw_singlepulse.py
Normal file
22
src/peakrdl_regblock/field_logic/sw_singlepulse.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from .bases import NextStateConditional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import FieldNode
|
||||
|
||||
class Singlepulse(NextStateConditional):
|
||||
comment = "singlepulse clears back to 0"
|
||||
def is_match(self, field: 'FieldNode') -> bool:
|
||||
return field.get_property('singlepulse')
|
||||
|
||||
def get_predicate(self, field: 'FieldNode') -> str:
|
||||
# TODO: make exporter promote this to an "else"?
|
||||
# Be mindful of sw/hw precedence. this would have to come last regardless
|
||||
return "1"
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
return [
|
||||
"next_c = '0;",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
56
src/peakrdl_regblock/field_logic/templates/counter_macros.sv
Normal file
56
src/peakrdl_regblock/field_logic/templates/counter_macros.sv
Normal file
@@ -0,0 +1,56 @@
|
||||
{% macro up_counter(field) -%}
|
||||
if({{field_logic.get_counter_incr_strobe(node)}}) begin // increment
|
||||
{%- if field_logic.counter_incrsaturates(node) %}
|
||||
if((({{node.width+1}})'(next_c) + {{field_logic.get_counter_incrvalue(node)}}) > {{field_logic.get_counter_incrsaturate_value(node)}}) begin // up-counter saturated
|
||||
next_c = {{field_logic.get_counter_incrsaturate_value(node)}};
|
||||
end else begin
|
||||
next_c = next_c + {{field_logic.get_counter_incrvalue(node)}};
|
||||
end
|
||||
{%- else %}
|
||||
{{field_logic.get_field_combo_identifier(node, "overflow")}} = ((({{node.width+1}})'(next_c) + {{field_logic.get_counter_incrvalue(node)}}) > {{get_value(2**node.width - 1)}});
|
||||
next_c = next_c + {{field_logic.get_counter_incrvalue(node)}};
|
||||
{%- endif %}
|
||||
load_next_c = '1;
|
||||
{%- if not field_logic.counter_incrsaturates(node) %}
|
||||
end else begin
|
||||
{{field_logic.get_field_combo_identifier(node, "overflow")}} = '0;
|
||||
{%- endif %}
|
||||
end
|
||||
{{field_logic.get_field_combo_identifier(node, "incrthreshold")}} = ({{field_logic.get_storage_identifier(node)}} >= {{field_logic.get_counter_incrthreshold_value(node)}});
|
||||
{%- if field_logic.counter_incrsaturates(node) %}
|
||||
{{field_logic.get_field_combo_identifier(node, "incrsaturate")}} = ({{field_logic.get_storage_identifier(node)}} >= {{field_logic.get_counter_incrsaturate_value(node)}});
|
||||
if(next_c > {{field_logic.get_counter_incrsaturate_value(node)}}) begin
|
||||
next_c = {{field_logic.get_counter_incrsaturate_value(node)}};
|
||||
load_next_c = '1;
|
||||
end
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
{% macro down_counter(field) -%}
|
||||
if({{field_logic.get_counter_decr_strobe(node)}}) begin // decrement
|
||||
{%- if field_logic.counter_decrsaturates(node) %}
|
||||
if(({{node.width+1}})'(next_c) < ({{field_logic.get_counter_decrvalue(node)}} + {{field_logic.get_counter_decrsaturate_value(node)}})) begin // down-counter saturated
|
||||
next_c = {{field_logic.get_counter_decrsaturate_value(node)}};
|
||||
end else begin
|
||||
next_c = next_c - {{field_logic.get_counter_decrvalue(node)}};
|
||||
end
|
||||
{%- else %}
|
||||
{{field_logic.get_field_combo_identifier(node, "underflow")}} = (next_c < ({{field_logic.get_counter_decrvalue(node)}}));
|
||||
next_c = next_c - {{field_logic.get_counter_decrvalue(node)}};
|
||||
{%- endif %}
|
||||
load_next_c = '1;
|
||||
{%- if not field_logic.counter_decrsaturates(node) %}
|
||||
end else begin
|
||||
{{field_logic.get_field_combo_identifier(node, "underflow")}} = '0;
|
||||
{%- endif %}
|
||||
end
|
||||
{{field_logic.get_field_combo_identifier(node, "decrthreshold")}} = ({{field_logic.get_storage_identifier(node)}} <= {{field_logic.get_counter_decrthreshold_value(node)}});
|
||||
{%- if field_logic.counter_decrsaturates(node) %}
|
||||
{{field_logic.get_field_combo_identifier(node, "decrsaturate")}} = ({{field_logic.get_storage_identifier(node)}} <= {{field_logic.get_counter_decrsaturate_value(node)}});
|
||||
if(next_c < {{field_logic.get_counter_decrsaturate_value(node)}}) begin
|
||||
next_c = {{field_logic.get_counter_decrsaturate_value(node)}};
|
||||
load_next_c = '1;
|
||||
end
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
35
src/peakrdl_regblock/field_logic/templates/field_storage.sv
Normal file
35
src/peakrdl_regblock/field_logic/templates/field_storage.sv
Normal file
@@ -0,0 +1,35 @@
|
||||
{%- import 'field_logic/templates/counter_macros.sv' as counter_macros with context -%}
|
||||
// Field: {{node.get_path()}}
|
||||
always_comb begin
|
||||
automatic logic [{{node.width-1}}:0] next_c = {{field_logic.get_storage_identifier(node)}};
|
||||
automatic logic load_next_c = '0;
|
||||
{%- for signal in extra_combo_signals %}
|
||||
{{field_logic.get_field_combo_identifier(node, signal.name)}} = {{signal.default_assignment}};
|
||||
{%- endfor %}
|
||||
{% for conditional in conditionals %}
|
||||
{%- if not loop.first %} else {% endif %}if({{conditional.get_predicate(node)}}) begin // {{conditional.comment}}
|
||||
{%- for assignment in conditional.get_assignments(node) %}
|
||||
{{assignment|indent}}
|
||||
{%- endfor %}
|
||||
end
|
||||
{%- endfor %}
|
||||
{%- if node.is_up_counter %}
|
||||
{{counter_macros.up_counter(node)}}
|
||||
{%- endif %}
|
||||
{%- if node.is_down_counter %}
|
||||
{{counter_macros.down_counter(node)}}
|
||||
{%- endif %}
|
||||
{{field_logic.get_field_combo_identifier(node, "next")}} = next_c;
|
||||
{{field_logic.get_field_combo_identifier(node, "load_next")}} = load_next_c;
|
||||
end
|
||||
always_ff {{get_always_ff_event(resetsignal)}} begin
|
||||
{% if reset is not none -%}
|
||||
if({{get_resetsignal(resetsignal)}}) begin
|
||||
{{field_logic.get_storage_identifier(node)}} <= {{reset}};
|
||||
end else {% endif %}if({{field_logic.get_field_combo_identifier(node, "load_next")}}) begin
|
||||
{{field_logic.get_storage_identifier(node)}} <= {{field_logic.get_field_combo_identifier(node, "next")}};
|
||||
end
|
||||
{%- if field_logic.has_next_q(node) %}
|
||||
{{field_logic.get_next_q_identifier(node)}} <= {{get_input_identifier(node)}};
|
||||
{%- endif %}
|
||||
end
|
||||
Reference in New Issue
Block a user