Add support for field paritycheck. #35

This commit is contained in:
Alex Mykyta
2023-05-15 22:53:17 -07:00
parent 3e691cb5fb
commit 0d82154b9d
16 changed files with 183 additions and 3 deletions

View File

@@ -1 +1 @@
__version__ = "0.14.0-rc1"
__version__ = "0.14.0-rc2"

View File

@@ -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]]

View File

@@ -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:
"""

View File

@@ -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))

View File

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

View File

@@ -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 %}
//--------------------------------------------------------------------------

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

View File

@@ -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)
)