def read_port(self, *, domain="sync", transparent_for=(), src_loc_at=0):
        """Request a read port.

        If :py:`domain` is :py:`"comb"`, the created read port is asynchronous and always enabled
        (with its enable input is tied to :py:`Const(1)`), and its data output always reflects
        the contents of the selected row. Otherwise, the created read port is synchronous,
        and its data output is updated with the contents of the selected row at each
        :ref:`active edge <lang-sync>` of :py:`domain` where the enable input is asserted.

        The :py:`transparent_for` parameter specifies the *transparency set* of this port: zero or
        more :class:`WritePort`\\ s, all of which must belong to the same memory and clock domain.
        If another port writes to a memory row at the same time as this port reads from the same
        memory row, and that write port is a part of the transparency set, then this port retrieves
        the new contents of the row; otherwise, this port retrieves the old contents of the row.

        If another write port belonging to a different clock domain updates a memory row that this
        port is reading at the same time, the behavior is undefined.

        The signature of the returned port is
        :py:`ReadPort.Signature(shape=self.shape, addr_width=ceil_log2(self.depth))`.

        Returns
        -------
        :class:`ReadPort`
        """
        if self._frozen:
            raise AlreadyElaborated("Cannot add a memory port to a memory that has already been elaborated")
        signature = ReadPort.Signature(shape=self.shape, addr_width=ceil_log2(self.depth))
        return ReadPort(signature, memory=self, domain=domain, transparent_for=transparent_for,
                        src_loc_at=1 + src_loc_at)
Request a read port.

        If :py:`domain` is :py:`"comb"`, the created read port is asynchronous and always enabled
        (with its enable input is tied to :py:`Const(1)`), and its data output always reflects
        the contents of the selected row. Otherwise, the created read port is synchronous,
        and its data output is updated with the contents of the selected row at each
        :ref:`active edge <lang-sync>` of :py:`domain` where the enable input is asserted.

        The :py:`transparent_for` parameter specifies the *transparency set* of this port: zero or
        more :class:`WritePort`\ s, all of which must belong to the same memory and clock domain.
        If another port writes to a memory row at the same time as this port reads from the same
        memory row, and that write port is a part of the transparency set, then this port retrieves
        the new contents of the row; otherwise, this port retrieves the old contents of the row.

        If another write port belonging to a different clock domain updates a memory row that this
        port is reading at the same time, the behavior is undefined.

        The signature of the returned port is
        :py:`ReadPort.Signature(shape=self.shape, addr_width=ceil_log2(self.depth))`.

        Returns
        -------
        :class:`ReadPort`
        
amaranth/lib/memory.py