Add support for field paritycheck. #35
This commit is contained in:
@@ -1 +1 @@
|
||||
__version__ = "0.14.0-rc1"
|
||||
__version__ = "0.14.0-rc2"
|
||||
|
||||
@@ -19,6 +19,7 @@ from .hwif import Hwif
|
||||
from .write_buffering import WriteBuffering
|
||||
from .read_buffering import ReadBuffering
|
||||
from .external_acks import ExternalWriteAckGenerator, ExternalReadAckGenerator
|
||||
from .parity import ParityErrorReduceGenerator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import SignalNode
|
||||
@@ -153,6 +154,7 @@ class RegblockExporter:
|
||||
self.dereferencer = Dereferencer(self)
|
||||
ext_write_acks = ExternalWriteAckGenerator(self)
|
||||
ext_read_acks = ExternalReadAckGenerator(self)
|
||||
parity = ParityErrorReduceGenerator(self)
|
||||
|
||||
# Validate that there are no unsupported constructs
|
||||
DesignValidator(self).do_validate()
|
||||
@@ -176,6 +178,7 @@ class RegblockExporter:
|
||||
"readback_implementation": readback_implementation,
|
||||
"ext_write_acks": ext_write_acks,
|
||||
"ext_read_acks": ext_read_acks,
|
||||
"parity": parity,
|
||||
"get_always_ff_event": self.dereferencer.get_always_ff_event,
|
||||
"ds": self.ds,
|
||||
"kwf": kwf,
|
||||
@@ -243,6 +246,8 @@ class DesignState:
|
||||
self.has_external_block = False
|
||||
self.has_external_addressable = False
|
||||
|
||||
self.has_paritycheck = False
|
||||
|
||||
# Track any referenced enums
|
||||
self.user_enums = [] # type: List[Type[UserEnum]]
|
||||
|
||||
|
||||
@@ -274,6 +274,19 @@ class FieldLogic:
|
||||
# Not sw modifiable
|
||||
return "1'b0"
|
||||
|
||||
def get_parity_identifier(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Returns the identifier for the stored 'golden' parity value of the field
|
||||
"""
|
||||
path = get_indexed_path(self.top_node, field)
|
||||
return f"field_storage.{path}.parity"
|
||||
|
||||
def get_parity_error_identifier(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Returns the identifier for whether the field currently has a parity error
|
||||
"""
|
||||
path = get_indexed_path(self.top_node, field)
|
||||
return f"field_combo.{path}.parity_error"
|
||||
|
||||
def has_next_q(self, field: 'FieldNode') -> bool:
|
||||
"""
|
||||
|
||||
@@ -53,6 +53,8 @@ class CombinationalStructGenerator(RDLStructGenerator):
|
||||
self.add_up_counter_members(node)
|
||||
if node.is_down_counter:
|
||||
self.add_down_counter_members(node)
|
||||
if node.get_property('paritycheck'):
|
||||
self.add_member("parity_error")
|
||||
self.pop_struct()
|
||||
|
||||
def add_up_counter_members(self, node: 'FieldNode') -> None:
|
||||
@@ -88,6 +90,8 @@ class FieldStorageStructGenerator(RDLStructGenerator):
|
||||
|
||||
if node.implements_storage:
|
||||
self.add_member("value", node.width)
|
||||
if node.get_property('paritycheck'):
|
||||
self.add_member("parity")
|
||||
|
||||
if self.field_logic.has_next_q(node):
|
||||
self.add_member("next_q", node.width)
|
||||
@@ -233,6 +237,7 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
'get_value': self.exp.dereferencer.get_value,
|
||||
'get_resetsignal': self.exp.dereferencer.get_resetsignal,
|
||||
'get_input_identifier': self.exp.hwif.get_input_identifier,
|
||||
'ds': self.ds,
|
||||
}
|
||||
self.add_content(self.field_storage_template.render(context))
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
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 %}
|
||||
@@ -13,22 +14,35 @@ always_comb begin
|
||||
{%- 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;
|
||||
|
||||
{%- if node.get_property('paritycheck') %}
|
||||
{{field_logic.get_parity_error_identifier(node)}} = ({{field_logic.get_parity_identifier(node)}} != ^{{field_logic.get_storage_identifier(node)}});
|
||||
{%- endif %}
|
||||
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}};
|
||||
{%- if node.get_property('paritycheck') %}
|
||||
{{field_logic.get_parity_identifier(node)}} <= ^{{reset}};
|
||||
{%- endif %}
|
||||
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")}};
|
||||
{%- if node.get_property('paritycheck') %}
|
||||
{{field_logic.get_parity_identifier(node)}} <= ^{{field_logic.get_field_combo_identifier(node, "next")}};
|
||||
{%- endif %}
|
||||
end
|
||||
|
||||
{%- if field_logic.has_next_q(node) %}
|
||||
{{field_logic.get_next_q_identifier(node)}} <= {{get_input_identifier(node)}};
|
||||
{%- endif %}
|
||||
|
||||
@@ -13,6 +13,11 @@ module {{ds.module_name}} (
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
{%- if ds.has_paritycheck %}
|
||||
|
||||
output logic parity_error,
|
||||
{%- endif %}
|
||||
|
||||
{{cpuif.port_declaration|indent(8)}}
|
||||
{%- if hwif.has_input_struct or hwif.has_output_struct %},{% endif %}
|
||||
|
||||
@@ -168,6 +173,22 @@ module {{ds.module_name}} (
|
||||
|
||||
{{field_logic.get_implementation()|indent}}
|
||||
|
||||
{%- if ds.has_paritycheck %}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Parity Error
|
||||
//--------------------------------------------------------------------------
|
||||
always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||
if({{get_resetsignal(cpuif.reset)}}) begin
|
||||
parity_error <= '0;
|
||||
end else begin
|
||||
automatic logic err = '0;
|
||||
{{parity.get_implementation()|indent(12)}}
|
||||
parity_error <= err;
|
||||
end
|
||||
end
|
||||
{%- endif %}
|
||||
|
||||
{%- if ds.has_buffered_read_regs %}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
34
src/peakrdl_regblock/parity.py
Normal file
34
src/peakrdl_regblock/parity.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from systemrdl.walker import WalkerAction
|
||||
|
||||
|
||||
from .forloop_generator import RDLForLoopGenerator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .exporter import RegblockExporter
|
||||
from systemrdl.node import FieldNode, AddressableNode
|
||||
|
||||
|
||||
class ParityErrorReduceGenerator(RDLForLoopGenerator):
|
||||
def __init__(self, exp: 'RegblockExporter') -> None:
|
||||
super().__init__()
|
||||
self.exp = exp
|
||||
|
||||
def get_implementation(self) -> str:
|
||||
content = self.get_content(self.exp.ds.top_node)
|
||||
if content is None:
|
||||
return ""
|
||||
return content
|
||||
|
||||
def enter_AddressableComponent(self, node: 'AddressableNode') -> WalkerAction:
|
||||
super().enter_AddressableComponent(node)
|
||||
if node.external:
|
||||
return WalkerAction.SkipDescendants
|
||||
return WalkerAction.Continue
|
||||
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
if node.get_property('paritycheck') and node.implements_storage:
|
||||
self.add_content(
|
||||
f"err |= {self.exp.field_logic.get_parity_error_identifier(node)};"
|
||||
)
|
||||
@@ -106,3 +106,14 @@ class DesignScanner(RDLListener):
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
if node.is_sw_writable and (node.msb < node.lsb):
|
||||
self.ds.has_writable_msb0_fields = True
|
||||
|
||||
if node.get_property('paritycheck') and node.implements_storage:
|
||||
self.ds.has_paritycheck = True
|
||||
|
||||
if node.get_property('reset') is None:
|
||||
self.msg.warning(
|
||||
f"Field '{node.inst_name}' includes parity check logic, but "
|
||||
"its reset value was not defined. Will result in an undefined "
|
||||
"value on the module's 'parity_error' output.",
|
||||
self.top_node.inst.property_src_ref.get('paritycheck', self.top_node.inst.inst_src_ref)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user