Switch to use regular non-namespaced package

This commit is contained in:
Alex Mykyta
2022-06-09 20:24:53 -07:00
parent 693040d145
commit 8d13a9d7fe
52 changed files with 26 additions and 27 deletions

View 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

View 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 []

View 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};"
)

View 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;",
]

View 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;",
]

View 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}"

View 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;",
]

View 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;",
]

View 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;",
]

View 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 %}

View 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