diff --git a/doc/props/field.rst b/doc/props/field.rst index 6da785c..181faa2 100644 --- a/doc/props/field.rst +++ b/doc/props/field.rst @@ -17,7 +17,7 @@ See ``onread`` singlepulse ^^^^^^^^^^^ -|NO| +|OK| sw ^^^ diff --git a/peakrdl/regblock/field_logic/__init__.py b/peakrdl/regblock/field_logic/__init__.py index 463ed6d..2e6bf6a 100644 --- a/peakrdl/regblock/field_logic/__init__.py +++ b/peakrdl/regblock/field_logic/__init__.py @@ -5,6 +5,7 @@ from systemrdl.rdltypes import PropertyReference, PrecedenceType 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 @@ -189,6 +190,8 @@ class FieldLogic: self.add_sw_conditional(sw_onwrite.WriteSet(self.exp), AssignmentPrecedence.SW_ONWRITE) self.add_sw_conditional(sw_onwrite.Write(self.exp), AssignmentPrecedence.SW_ONWRITE) + self.add_sw_conditional(sw_singlepulse.Singlepulse(self.exp), AssignmentPrecedence.SW_SINGLEPULSE) + self.add_hw_conditional(hw_write.AlwaysWrite(self.exp), AssignmentPrecedence.HW_WRITE) self.add_hw_conditional(hw_write.WELWrite(self.exp), AssignmentPrecedence.HW_WRITE) self.add_hw_conditional(hw_write.WEWrite(self.exp), AssignmentPrecedence.HW_WRITE) diff --git a/peakrdl/regblock/field_logic/bases.py b/peakrdl/regblock/field_logic/bases.py index 3f3521c..fa70773 100644 --- a/peakrdl/regblock/field_logic/bases.py +++ b/peakrdl/regblock/field_logic/bases.py @@ -24,6 +24,7 @@ class AssignmentPrecedence(enum.IntEnum): # Software access assignment groups SW_ONREAD = 5000 SW_ONWRITE = 4000 + SW_SINGLEPULSE = 3000 # Hardware access assignment groups HW_WRITE = 3000 diff --git a/peakrdl/regblock/field_logic/sw_singlepulse.py b/peakrdl/regblock/field_logic/sw_singlepulse.py new file mode 100644 index 0000000..0b35e8c --- /dev/null +++ b/peakrdl/regblock/field_logic/sw_singlepulse.py @@ -0,0 +1,23 @@ +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]: + field_path = self.get_field_path(field) + return [ + f"field_combo.{field_path}.next = '0;", + f"field_combo.{field_path}.load_next = '1;", + ] diff --git a/test/test_singlepulse/__init__.py b/test/test_singlepulse/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test_singlepulse/regblock.rdl b/test/test_singlepulse/regblock.rdl new file mode 100644 index 0000000..82ff060 --- /dev/null +++ b/test/test_singlepulse/regblock.rdl @@ -0,0 +1,8 @@ +addrmap top { + reg { + field { + sw=rw; hw=r; + singlepulse; + } f[0:0] = 0; + } r1; +}; diff --git a/test/test_singlepulse/tb_template.sv b/test/test_singlepulse/tb_template.sv new file mode 100644 index 0000000..762c6c9 --- /dev/null +++ b/test/test_singlepulse/tb_template.sv @@ -0,0 +1,56 @@ +{% extends "lib/templates/tb_base.sv" %} + +{% block seq %} + {% sv_line_anchor %} + int event_count; + + ##1; + cb.rst <= '0; + ##1; + + // No pulse if writing zero + event_count = 0; + fork + begin + ##0; + forever begin + @cb; + if(cb.hwif_out.r1.f.value) begin + event_count++; + end + end + end + + begin + cpuif.write('h0, 'h0); + repeat(5) @cb; + end + join_any + disable fork; + assert(event_count == 0) else $error("Observed excess singlepulse events: %0d", event_count); + + // single pulse + event_count = 0; + fork + begin + ##0; + forever begin + @cb; + if(cb.hwif_out.r1.f.value) begin + event_count++; + end + end + end + + begin + cpuif.write('h0, 'h1); + repeat(5) @cb; + end + join_any + disable fork; + assert(event_count == 1) else $error("Observed incorrect number of singlepulse events: %0d", event_count); + + // auto-clears + cpuif.assert_read('h0, 'h0); + +{% endblock %} diff --git a/test/test_singlepulse/testcase.py b/test/test_singlepulse/testcase.py new file mode 100644 index 0000000..b458d3c --- /dev/null +++ b/test/test_singlepulse/testcase.py @@ -0,0 +1,5 @@ +from ..lib.regblock_testcase import RegblockTestCase + +class Test(RegblockTestCase): + def test_dut(self): + self.run_test()