Skip to content

Commit f0d73fb

Browse files
committed
Minor documentation improvements and add a test with a register self-loop.
1 parent 81fa28b commit f0d73fb

2 files changed

Lines changed: 32 additions & 12 deletions

File tree

pyrtl/gate_graph.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class Gate:
119119
:attr:`~Gate.dest_bitwidth` will be ``None``. PyRTL does not have
120120
:attr:`ops<.LogicNet.op>` with multiple :attr:`~.LogicNet.dests`.
121121
122-
3. The :class:`Gate` has is a new :attr:`~Gate.dest_fanout` attribute, which has no
122+
3. The :class:`Gate` has a new :attr:`~Gate.dest_fanout` attribute, which has no
123123
equivalent in the :class:`.LogicNet`/:class:`.WireVector` representation.
124124
:attr:`~Gate.dest_fanout` is a list of the :class:`Gates<Gate>` that use this
125125
:class:`Gate`'s output.
@@ -168,7 +168,7 @@ class Gate:
168168
track of the current object's type as we follow arrows in the graph, like we did
169169
with :class:`LogicNet` and :class:`WireVector`. Everything is a :class:`Gate`.
170170
171-
See the documentation for :class:`GateGraph` for examples.
171+
For usage examples, see :class:`GateGraph` and :class:`Gate`'s documentation below.
172172
"""
173173

174174
op: str
@@ -233,7 +233,8 @@ class Gate:
233233
234234
.. note::
235235
236-
The same ``Gate`` may appear multiple times in ``args``.
236+
The same ``Gate`` may appear multiple times in ``args``. A :class:`.Register`
237+
``Gate`` may be its own ``arg``, creating a self-loop.
237238
238239
.. doctest only::
239240
@@ -312,9 +313,11 @@ class Gate:
312313
For each :class:`Gate` ``dest`` in ``self.dest_fanout``, ``self`` is in
313314
``dest.args``.
314315
315-
..note::
316+
.. note::
316317
317-
The same :class:`Gate` may appear multiple times in ``dest_fanout``.
318+
The same :class:`Gate` may appear multiple times in ``dest_fanout``. A
319+
:class:`.Register` ``Gate`` may appear in its own ``dest_fanout``, creating a
320+
self-loop.
318321
319322
.. doctest only::
320323
@@ -379,7 +382,7 @@ def __init__(
379382
:class:`.WireVector`. In this first phase, the register ``Gate``'s ``op`` is
380383
temporarily set to ``R``, which is the :class:`.Register`'s ``_code``. This
381384
placeholder is needed to resolve other ``Gate``'s references to the register
382-
in the second phase. In the second phase, the register gate's remaining
385+
in the second phase. In the second phase, the register ``Gate``'s remaining
383386
fields are populated from the register's :class:`.LogicNet`. In the second
384387
phase, the register ``Gate``'s ``op`` is changed to ``r``, which is the
385388
:class:`.LogicNet`'s :attr:`~.LogicNet.op`.
@@ -391,8 +394,8 @@ def __init__(
391394
:class:`.Register`.
392395
393396
:param args: A :class:`list` of ``Gates`` that are inputs to this ``Gate``. This
394-
corresponds to :attr:`.LogicNet.args`, except that each of these ``args`` is
395-
a ``Gate``.
397+
corresponds to :attr:`.LogicNet.args`, except that each of a ``Gate``'s
398+
``args`` is a ``Gate``.
396399
"""
397400
self.op_param = None
398401
if args is None:
@@ -484,8 +487,9 @@ def __str__(self):
484487
- :attr:`~Gate.args` is ``[<Gate that produces tmp12>]``.
485488
486489
- :attr:`~Gate.op_param` is ``(0, 1, 2, 3, 4, 5, 6, 7)``, written as ``sel``
487-
because a ``slice``'s ``op_param`` determines the selected bits. This improves
488-
readability.
490+
because a ``slice``'s :attr:`~Gate.op_param` determines the selected bits.
491+
This improves readability by indicating what the :attr:`~Gate.op_param` means
492+
for the :attr:`~Gate.op`.
489493
"""
490494
if self.dest_name is None:
491495
dest = ""
@@ -638,8 +642,9 @@ class GateGraph:
638642
defines the register's :attr:`~.Register.next` value (which is the register
639643
:class:`Gate`'s :attr:`~Gate.args`) can depend on the register's current value
640644
(which is the register :class:`Gate`'s ``dest``). Watch out for infinite loops
641-
when traversing a :class:`GateGraph` with registers, if you keep following
642-
:attr:`~Gate.dest_fanout` references you may end up back where you started.
645+
when traversing a :class:`GateGraph` with registers. For example, if you keep
646+
following :attr:`~Gate.dest_fanout` references, you may end up back where you
647+
started.
643648
"""
644649

645650
gates: list[Gate]

tests/test_gate_graph.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def test_gate_attrs(self):
9999

100100
a_gate = gate_graph.get_gate("a")
101101
self.assertEqual(a_gate.op, "I")
102+
self.assertEqual(a_gate.args, [])
102103

103104
b_gate = gate_graph.get_gate("b")
104105
self.assertEqual(b_gate.op, "C")
@@ -199,6 +200,20 @@ def test_register_gate_backward(self):
199200

200201
self.assertEqual(plus_gate.args[0], counter_gate)
201202

203+
def test_register_self_loop(self):
204+
"""Test a register that sets its next value directly from itself.
205+
206+
This is an unusual case that creates a self-loop in the ``GateGraph``.
207+
"""
208+
r = pyrtl.Register(name="r", bitwidth=1)
209+
r.next <<= r
210+
211+
gate_graph = pyrtl.GateGraph()
212+
r_gate = gate_graph.get_gate("r")
213+
self.assertEqual(r_gate.args[0], r_gate)
214+
self.assertEqual(r_gate.dest_fanout[0], r_gate)
215+
self.assertEqual(str(r_gate), "r/1 = reg(r/1) [reset_value=0]")
216+
202217
def test_memblock(self):
203218
mem = pyrtl.MemBlock(name="mem", bitwidth=8, addrwidth=2)
204219

0 commit comments

Comments
 (0)