@@ -729,41 +729,96 @@ def __ior__(self, _):
729729
730730
731731class Register (WireVector ):
732- """A WireVector with a register state element embedded .
732+ """A WireVector with an embedded register state element.
733733
734- Registers only update their outputs on posedge of an implicit clock signal.
735- The "value" in the current cycle can be accessed by just referencing the
736- Register itself. To set the value for the next cycle (after the next
737- posedge) you write to the property :attr:`~.Register.next` with the ``<<=``
738- operator. For example, if you want to specify a counter it would look like:
739- ``a.next <<= a + 1``
734+ Registers only update their outputs on the rising edges of an implicit clock signal.
735+ The "value" in the current cycle can be accessed by referencing the Register itself.
736+ To set the value for the next cycle (after the next rising clock edge), set the
737+ :attr:`.Register.next` property with the ``<<=`` operator.
738+
739+ Registers reset to zero by default, and reside in the same clock domain.
740+
741+ Example::
742+
743+ counter = pyrtl.Register(bitwidth=8)
744+ counter.next <<= counter + 1
745+
746+ This builds a zero-initialized 8-bit counter. The second line sets the counter's
747+ value in the next cycle (``counter.next``) to the counter's value in the current
748+ cycle (``counter``), plus one.
740749
741750 """
742751 _code = 'R'
743752
744- # When the register is called as such: r.next <<= foo
745- # the sequence of actions that happens is:
746- # 1) The property .next is called to get the "value" of r.next
747- # 2) The "value" is then passed to __ilshift__
753+ # When a register's next value is assigned, the following occurs:
748754 #
749- # The resulting behavior should enforce the following:
750- # r.next <<= 5 -- good
751- # a <<= r -- good
752- # r <<= 5 -- error
753- # a <<= r.next -- error
754- # r.next = 5 -- error
755-
755+ # 1. The register's `.next` property is retrieved. Register.next returns an instance
756+ # of Register._Next.
757+ # 2. __ilshift__ is invoked on the returned instance of Register._Next.
758+ #
759+ # So `reg.next <<= foo` effectively does the following:
760+ #
761+ # reg.next = Register._Next(reg)
762+ # reg.next.__ilshift__(reg, foo)
763+ #
764+ # The following behavior is expected:
765+ #
766+ # reg.next <<= 5 # good
767+ # a <<= reg # good
768+ # reg <<= 5 # error
769+ # a <<= reg.next # error
770+ # reg.next = 5 # error
756771 class _Next (object ):
757- """ This is the type returned by "r .next". """
772+ """Type returned by the ``Register .next`` property.
758773
774+ This class allows unconditional assignments (``<<=``, ``__ilshift__``) and
775+ conditional assignments (``|=``, ``__ior__``) on ``Register.next``. Registers
776+ themselves do not support assignments, so ``Register.__ilshift__`` and
777+ ``Register.__ior__`` throw errors.
778+
779+ ``__ilshift__`` and ``__ior__`` must both return ``self`` because::
780+
781+ x <<= y
782+
783+ is equivalent to::
784+
785+ x = x.__ilshift__(y)
786+
787+ Note how ``__ilshift__``'s return value is assigned to ``x``, see
788+ https://docs.python.org/3/library/operator.html#in-place-operators
789+
790+ ``__ilshift__`` and ``__ior__`` both return ``self`` and Register's @next.setter
791+ checks that Register.next is assigned to an instance of _Next.
792+
793+ """
759794 def __init__ (self , reg ):
760795 self .reg = reg
761796
762797 def __ilshift__ (self , other ):
763- return self .reg ._next_ilshift (other )
798+ from .corecircuits import as_wires
799+ other = as_wires (other , bitwidth = self .reg .bitwidth )
800+ if self .reg .bitwidth is None :
801+ self .reg .bitwidth = other .bitwidth
802+
803+ if self .reg .reg_in is not None :
804+ raise PyrtlError ('error, .next value should be set once and only once' )
805+ self .reg ._build (other )
806+
807+ return self
764808
765809 def __ior__ (self , other ):
766- return self .reg ._next_ior (other )
810+ from .conditional import _build
811+ from .corecircuits import as_wires
812+ other = as_wires (other , bitwidth = self .reg .bitwidth )
813+ if not self .reg .bitwidth :
814+ raise PyrtlError ('Conditional assignment only defined on '
815+ 'Registers with pre-defined bitwidths' )
816+
817+ if self .reg .reg_in is not None :
818+ raise PyrtlError ('error, .next value should be set once and only once' )
819+ _build (self .reg , other )
820+
821+ return self
767822
768823 def __bool__ (self ):
769824 """ Use of a _next in a statement like "a or b" is forbidden."""
@@ -774,23 +829,17 @@ def __bool__(self):
774829
775830 __nonzero__ = __bool__ # for Python 2 and 3 compatibility
776831
777- class _NextSetter (object ):
778- """ This is the type returned by __ilshift__ which r.next will be assigned. """
779-
780- def __init__ (self , rhs , is_conditional ):
781- self .rhs = rhs
782- self .is_conditional = is_conditional
783-
784832 def __init__ (self , bitwidth : int , name : str = '' , reset_value : int = None ,
785833 block : Block = None ):
786834 """Construct a register.
787835
788836 :param bitwidth: Number of bits to represent this register.
789- :param name: The name of the wire. Must be unique. If none is provided,
790- one will be autogenerated.
837+ :param name: The name of the register's current value (``reg``, not
838+ ``reg.next``). Must be unique. If none is provided, one will be
839+ autogenerated.
791840 :param reset_value: Value to initialize this register to during
792841 simulation and in any code (e.g. Verilog) that is exported.
793- Defaults to 0, but can be explicitly overridden at simulation time.
842+ Defaults to 0. Can be overridden at simulation time.
794843 :param block: The block under which the wire should be placed. Defaults
795844 to the working block.
796845
@@ -812,10 +861,7 @@ def __init__(self, bitwidth: int, name: str = '', reset_value: int = None,
812861
813862 @property
814863 def next (self ):
815- """
816- This property is the way to set what the WireVector will be the next
817- cycle (aka, it is before the D-Latch)
818- """
864+ """Sets the Register's value for the next cycle (it is before the D-Latch)."""
819865 return Register ._Next (self )
820866
821867 def __ilshift__ (self , other ):
@@ -824,36 +870,15 @@ def __ilshift__(self, other):
824870 def __ior__ (self , other ):
825871 raise PyrtlError ('error, you cannot set registers directly, net .next instead' )
826872
827- def _next_ilshift (self , other ):
828- from .corecircuits import as_wires
829- other = as_wires (other , bitwidth = self .bitwidth )
830- if self .bitwidth is None :
831- self .bitwidth = other .bitwidth
832- return Register ._NextSetter (other , is_conditional = False )
833-
834- def _next_ior (self , other ):
835- from .corecircuits import as_wires
836- other = as_wires (other , bitwidth = self .bitwidth )
837- if not self .bitwidth :
838- raise PyrtlError ('Conditional assignment only defined on '
839- 'Registers with pre-defined bitwidths' )
840- return Register ._NextSetter (other , is_conditional = True )
841-
842873 @next .setter
843- def next (self , nextsetter ):
844- from .conditional import _build
845- if not isinstance (nextsetter , Register ._NextSetter ):
874+ def next (self , other ):
875+ if not isinstance (other , Register ._Next ):
846876 raise PyrtlError ('error, .next should be set with "<<=" or "|=" operators' )
847- elif self .reg_in is not None :
848- raise PyrtlError ('error, .next value should be set once and only once' )
849- elif nextsetter .is_conditional :
850- _build (self , nextsetter .rhs )
851- else :
852- self ._build (nextsetter .rhs )
853877
854878 def _build (self , next ):
855- # this actually builds the register which might be from directly setting
856- # the property "next" or delayed when there is a conditional assignement
879+ # Actually build the register. This happens immediately when setting the `next`
880+ # property. Under conditional assignment, register build is delayed until the
881+ # conditional assignment is _finalized.
857882 self .reg_in = next
858883 net = LogicNet ('r' , None , args = (self .reg_in ,), dests = (self ,))
859884 working_block ().add_net (net )
@@ -888,13 +913,13 @@ def __getattr__(self, name: str):
888913 def __setattr__ (self , name , value ):
889914 '''Forward all attribute assignments to the wrapped WireVector.
890915
891- This is needed to make ``reg.next <<= foo`` work, because that
892- expands to::
916+ This is needed to make ``reg.next <<= foo`` work, because that expands to::
893917
894918 reg.next = reg.next.__ilshift__(foo)
895919
896- And this attribute assignment must be forwarded to the underlying
897- Register.
920+ See https://docs.python.org/3/library/operator.html#in-place-operators
921+
922+ This attribute assignment must be forwarded to the underlying Register.
898923
899924 '''
900925 self .wire .__setattr__ (name , value )
0 commit comments