Implement RFC 39: Change semantics of no-argument m.Case().

This commit is contained in:
Wanda 2024-01-13 12:35:52 +01:00 committed by Catherine
parent eb1c55859e
commit 86d14f584e
5 changed files with 25 additions and 8 deletions

View file

@ -542,7 +542,7 @@ class Value(metaclass=ABCMeta):
continue
matches.append(self == pattern)
if not matches:
return Const(1)
return Const(0)
elif len(matches) == 1:
return matches[0]
else:

View file

@ -343,19 +343,31 @@ class Module(_ModuleBuilderRoot, Elaboratable):
yield
self._flush_ctrl()
# If none of the provided cases can possibly be true, omit this branch completely.
# This needs to be differentiated from no cases being provided in the first place,
# which means the branch will always match.
# Likewise, omit this branch if another branch with this exact set of patterns already
# exists (since otherwise we'd overwrite the previous branch's slot in the dict).
if not (patterns and not new_patterns) and new_patterns not in switch_data["cases"]:
if new_patterns and new_patterns not in switch_data["cases"]:
switch_data["cases"][new_patterns] = self._statements
switch_data["case_src_locs"][new_patterns] = src_loc
finally:
self._ctrl_context = "Switch"
self._statements = _outer_case
@contextmanager
def Default(self):
return self.Case()
self._check_context("Default", context="Switch")
src_loc = tracer.get_src_loc(src_loc_at=1)
switch_data = self._get_ctrl("Switch")
try:
_outer_case, self._statements = self._statements, []
self._ctrl_context = None
yield
self._flush_ctrl()
if () not in switch_data["cases"]:
switch_data["cases"][()] = self._statements
switch_data["case_src_locs"][()] = src_loc
finally:
self._ctrl_context = "Switch"
self._statements = _outer_case
@contextmanager
def FSM(self, reset=None, domain="sync", name="fsm"):

View file

@ -15,6 +15,8 @@ Migrating from version 0.4
Apply the following changes to code written against Amaranth 0.4 to migrate it to version 0.5:
* Replace uses of ``m.Case()`` with no patterns with ``m.Default()``
* Replace uses of ``Value.matches()`` with no patterns with ``Const(1)``
* Update uses of :func:`amaranth.utils.log2_int(need_pow2=False)` to :func:`amaranth.utils.ceil_log2`
* Update uses of :func:`amaranth.utils.log2_int(need_pow2=True)` to :func:`amaranth.utils.exact_log2`
@ -23,8 +25,10 @@ Implemented RFCs
----------------
.. _RFC 17: https://amaranth-lang.org/rfcs/0017-remove-log2-int.html
.. _RFC 39: https://amaranth-lang.org/rfcs/0039-empty-case.html
* `RFC 17`_: Remove ``log2_int``
* `RFC 39`_: Change semantics of no-argument ``m.Case()``
Language changes
@ -34,6 +38,8 @@ Language changes
* Added: :class:`ast.Slice` objects have been made const-castable.
* Added: :func:`amaranth.utils.ceil_log2`, :func:`amaranth.utils.exact_log2`. (`RFC 17`_)
* Changed: ``m.Case()`` with no patterns is never active instead of always active. (`RFC 39`_)
* Changed: ``Value.matches()`` with no patterns is ``Const(0)`` instead of ``Const(1)``. (`RFC 39`_)
* Deprecated: :func:`amaranth.utils.log2_int`. (`RFC 17`_)
* Removed: (deprecated in 0.4) :meth:`Const.normalize`. (`RFC 5`_)
* Removed: (deprecated in 0.4) :class:`ast.Sample`, :class:`ast.Past`, :class:`ast.Stable`, :class:`ast.Rose`, :class:`ast.Fell`.

View file

@ -682,7 +682,7 @@ class OperatorTestCase(FHDLTestCase):
def test_matches(self):
s = Signal(4)
self.assertRepr(s.matches(), "(const 1'd1)")
self.assertRepr(s.matches(), "(const 1'd0)")
self.assertRepr(s.matches(1), """
(== (sig s) (const 1'd1))
""")

View file

@ -366,7 +366,7 @@ class DSLTestCase(FHDLTestCase):
)
""")
def test_Switch_default_Case(self):
def test_Switch_empty_Case(self):
m = Module()
with m.Switch(self.w1):
with m.Case(3):
@ -378,7 +378,6 @@ class DSLTestCase(FHDLTestCase):
(
(switch (sig w1)
(case 0011 (eq (sig c1) (const 1'd1)))
(default (eq (sig c2) (const 1'd1)))
)
)
""")