Exemple #1
0
def fifo_payload(channels):
    address_width = max(
        rtlink.get_address_width(channel.interface.o) for channel in channels)
    data_width = max(
        rtlink.get_data_width(channel.interface.o) for channel in channels)

    layout = [("channel", bits_for(len(channels) - 1)), ("timestamp", 64)]
    if address_width:
        layout.append(("address", address_width))
    if data_width:
        layout.append(("data", data_width))

    return layout
Exemple #2
0
def output_network_payload(channels, glbl_fine_ts_width):
    address_width = max(rtlink.get_address_width(channel.interface.o)
                        for channel in channels)
    data_width = max(rtlink.get_data_width(channel.interface.o)
                     for channel in channels)

    layout = [("channel", bits_for(len(channels)-1))]
    if glbl_fine_ts_width:
        layout.append(("fine_ts", glbl_fine_ts_width))
    if address_width:
        layout.append(("address", address_width))
    if data_width:
        layout.append(("data", data_width))

    return layout
Exemple #3
0
def output_network_payload(channels, glbl_fine_ts_width):
    address_width = max(
        rtlink.get_address_width(channel.interface.o) for channel in channels)
    data_width = max(
        rtlink.get_data_width(channel.interface.o) for channel in channels)

    layout = [("channel", bits_for(len(channels) - 1))]
    if glbl_fine_ts_width:
        layout.append(("fine_ts", glbl_fine_ts_width))
    if address_width:
        layout.append(("address", address_width))
    if data_width:
        layout.append(("data", data_width))

    return layout
Exemple #4
0
def fifo_payload(channels):
    address_width = max(rtlink.get_address_width(channel.interface.o)
                        for channel in channels)
    data_width = max(rtlink.get_data_width(channel.interface.o)
                     for channel in channels)

    layout = [
        ("channel", bits_for(len(channels)-1)),
        ("timestamp", 64)
    ]
    if address_width:
        layout.append(("address", address_width))
    if data_width:
        layout.append(("data", data_width))

    return layout
Exemple #5
0
    def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", counter.width + fine_ts_width))
        # ev must be valid 1 cycle before we to account for the latency in
        # generating replace, sequence_error and collision
        self.ev = Record(ev_layout)

        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2

        self.underflow = Signal()  # valid 1 cycle after we, pulsed
        self.sequence_error = Signal()
        self.collision = Signal()
        self.busy = Signal()  # pulsed

        # # #

        # FIFO
        fifo = ClockDomainsRenamer({
            "write": "rsys",
            "read": "rio"
        })(AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision = Signal()
        any_error = Signal()
        if interface.enable_replace:
            # Note: replace may be asserted at the same time as collision
            # when addresses are different. In that case, it is a collision.
            self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp)
            # Detect sequence errors on coarse timestamps only
            # so that they are mutually exclusive with collision errors.
        self.sync.rsys += sequence_error.eq(
            self.ev.timestamp[fine_ts_width:] < buf.timestamp[fine_ts_width:])
        if interface.enable_replace:
            if address_width:
                different_addresses = self.ev.address != buf.address
            else:
                different_addresses = 0
            if fine_ts_width:
                self.sync.rsys += collision.eq(
                    (self.ev.timestamp[fine_ts_width:] ==
                     buf.timestamp[fine_ts_width:])
                    & ((self.ev.timestamp[:fine_ts_width] !=
                        buf.timestamp[:fine_ts_width])
                       | different_addresses))
        else:
            self.sync.rsys += collision.eq(self.ev.timestamp[fine_ts_width:] ==
                                           buf.timestamp[fine_ts_width:])
        self.comb += [
            any_error.eq(sequence_error | collision),
            self.sequence_error.eq(self.we & sequence_error),
            self.collision.eq(self.we & collision)
        ]

        # Buffer read and FIFO write
        self.comb += fifo_in.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:] < counter.value_sys +
            guard_io_cycles)
        self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        self.underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(self.we & ~replace & ~any_error,
                   fifo.we.eq(1)
                )
            )

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rsys += [
            buf_just_written.eq(0),
            If(self.we & ~any_error, buf_just_written.eq(1), buf_pending.eq(1),
               buf.eq(self.ev))
        ]
        self.comb += self.writable.eq(fifo.writable)

        # Buffer output of FIFO to improve timing
        dout_stb = Signal()
        dout_ack = Signal()
        dout = Record(ev_layout)
        self.sync.rio += \
            If(fifo.re,
                dout_stb.eq(1),
                dout.eq(fifo_out)
            ).Elif(dout_ack,
                dout_stb.eq(0)
            )
        self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

        # latency compensation
        if interface.delay:
            counter_rtio = Signal.like(counter.value_rtio)
            self.sync.rtio += counter_rtio.eq(counter.value_rtio -
                                              interface.delay + 1)
        else:
            counter_rtio = counter.value_rtio

        # FIFO read through buffer
        self.comb += [
            dout_ack.eq(dout.timestamp[fine_ts_width:] == counter_rtio),
            interface.stb.eq(dout_stb & dout_ack)
        ]

        busy_transfer = BlindTransfer()
        self.submodules += busy_transfer
        self.comb += [
            busy_transfer.i.eq(interface.stb & interface.busy),
            self.busy.eq(busy_transfer.o),
        ]

        if data_width:
            self.comb += interface.data.eq(dout.data)
        if address_width:
            self.comb += interface.address.eq(dout.address)
        if fine_ts_width:
            self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
Exemple #6
0
    def __init__(self, channels, full_ts_width=63, guard_io_cycles=20):
        data_width = max(rtlink.get_data_width(c.interface)
                         for c in channels)
        address_width = max(rtlink.get_address_width(c.interface)
                            for c in channels)
        fine_ts_width = max(rtlink.get_fine_ts_width(c.interface)
                            for c in channels)

        self.data_width = data_width
        self.address_width = address_width
        self.fine_ts_width = fine_ts_width

        # CSRs
        self.kcsrs = _KernelCSRs(bits_for(len(channels)-1),
                                 data_width, address_width,
                                 full_ts_width)

        # Clocking/Reset
        # Create rsys, rio and rio_phy domains based on sys and rtio
        # with reset controlled by CSR.
        self.clock_domains.cd_rsys = ClockDomain()
        self.clock_domains.cd_rio = ClockDomain()
        self.clock_domains.cd_rio_phy = ClockDomain()
        self.comb += [
            self.cd_rsys.clk.eq(ClockSignal()),
            self.cd_rsys.rst.eq(self.kcsrs.reset.storage)
        ]
        self.comb += self.cd_rio.clk.eq(ClockSignal("rtio"))
        self.specials += AsyncResetSynchronizer(
            self.cd_rio,
            self.kcsrs.reset.storage | ResetSignal("rtio",
                                                   allow_reset_less=True))
        self.comb += self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
        self.specials += AsyncResetSynchronizer(
            self.cd_rio_phy,
            self.kcsrs.reset_phy.storage | ResetSignal("rtio",
                                                       allow_reset_less=True))

        # Managers
        self.submodules.counter = _RTIOCounter(full_ts_width - fine_ts_width)

        i_datas, i_timestamps = [], []
        o_statuses, i_statuses = [], []
        sel = self.kcsrs.chan_sel.storage
        for n, channel in enumerate(channels):
            if isinstance(channel, LogChannel):
                i_datas.append(0)
                i_timestamps.append(0)
                i_statuses.append(0)
                continue

            selected = Signal()
            self.comb += selected.eq(sel == n)

            o_manager = _OutputManager(channel.interface.o, self.counter,
                                       channel.ofifo_depth, guard_io_cycles)
            self.submodules += o_manager

            if hasattr(o_manager.ev, "data"):
                self.comb += o_manager.ev.data.eq(
                    self.kcsrs.o_data.storage)
            if hasattr(o_manager.ev, "address"):
                self.comb += o_manager.ev.address.eq(
                    self.kcsrs.o_address.storage)
            ts_shift = (len(self.kcsrs.o_timestamp.storage)
                        - len(o_manager.ev.timestamp))
            self.comb += o_manager.ev.timestamp.eq(
                self.kcsrs.o_timestamp.storage[ts_shift:])

            self.comb += o_manager.we.eq(selected & self.kcsrs.o_we.re)

            underflow = Signal()
            sequence_error = Signal()
            collision = Signal()
            busy = Signal()
            self.sync.rsys += [
                If(selected & self.kcsrs.o_underflow_reset.re,
                   underflow.eq(0)),
                If(selected & self.kcsrs.o_sequence_error_reset.re,
                   sequence_error.eq(0)),
                If(selected & self.kcsrs.o_collision_reset.re,
                   collision.eq(0)),
                If(selected & self.kcsrs.o_busy_reset.re,
                   busy.eq(0)),
                If(o_manager.underflow, underflow.eq(1)),
                If(o_manager.sequence_error, sequence_error.eq(1)),
                If(o_manager.collision, collision.eq(1)),
                If(o_manager.busy, busy.eq(1))
            ]
            o_statuses.append(Cat(~o_manager.writable,
                                  underflow,
                                  sequence_error,
                                  collision,
                                  busy))

            if channel.interface.i is not None:
                i_manager = _InputManager(channel.interface.i, self.counter,
                                          channel.ififo_depth)
                self.submodules += i_manager

                if hasattr(i_manager.ev, "data"):
                    i_datas.append(i_manager.ev.data)
                else:
                    i_datas.append(0)
                if channel.interface.i.timestamped:
                    ts_shift = (len(self.kcsrs.i_timestamp.status)
                                - len(i_manager.ev.timestamp))
                    i_timestamps.append(i_manager.ev.timestamp << ts_shift)
                else:
                    i_timestamps.append(0)

                self.comb += i_manager.re.eq(selected & self.kcsrs.i_re.re)

                overflow = Signal()
                self.sync.rsys += [
                    If(selected & self.kcsrs.i_overflow_reset.re,
                       overflow.eq(0)),
                    If(i_manager.overflow,
                       overflow.eq(1))
                ]
                i_statuses.append(Cat(~i_manager.readable, overflow))

            else:
                i_datas.append(0)
                i_timestamps.append(0)
                i_statuses.append(0)
        if data_width:
            self.comb += self.kcsrs.i_data.status.eq(Array(i_datas)[sel])
        self.comb += [
            self.kcsrs.i_timestamp.status.eq(Array(i_timestamps)[sel]),
            self.kcsrs.o_status.status.eq(Array(o_statuses)[sel]),
            self.kcsrs.i_status.status.eq(Array(i_statuses)[sel])
        ]

        # Counter access
        self.sync += \
           If(self.kcsrs.counter_update.re,
               self.kcsrs.counter.status.eq(self.counter.value_sys
                                                << fine_ts_width)
           )
Exemple #7
0
    def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", counter.width + fine_ts_width))
        # ev must be valid 1 cycle before we to account for the latency in
        # generating replace, sequence_error and collision
        self.ev = Record(ev_layout)

        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2

        self.underflow = Signal()  # valid 1 cycle after we, pulsed
        self.sequence_error = Signal()
        self.collision = Signal()
        self.busy = Signal()  # pulsed

        # # #

        # FIFO
        fifo = ClockDomainsRenamer({"write": "rsys", "read": "rio"})(
            AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision = Signal()
        any_error = Signal()
        if interface.enable_replace:
            # Note: replace may be asserted at the same time as collision
            # when addresses are different. In that case, it is a collision.
            self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp)
            # Detect sequence errors on coarse timestamps only
            # so that they are mutually exclusive with collision errors.
        self.sync.rsys += sequence_error.eq(self.ev.timestamp[fine_ts_width:] <
                                            buf.timestamp[fine_ts_width:])
        if interface.enable_replace:
            if address_width:
                different_addresses = self.ev.address != buf.address
            else:
                different_addresses = 0
            if fine_ts_width:
                self.sync.rsys += collision.eq(
                    (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
                    & ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])
                       |different_addresses))
        else:
            self.sync.rsys += collision.eq(
                self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
        self.comb += [
            any_error.eq(sequence_error | collision),
            self.sequence_error.eq(self.we & sequence_error),
            self.collision.eq(self.we & collision)
        ]

        # Buffer read and FIFO write
        self.comb += fifo_in.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:]
                < counter.value_sys + guard_io_cycles)
        self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        self.underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(self.we & ~replace & ~any_error,
                   fifo.we.eq(1)
                )
            )

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rsys += [
            buf_just_written.eq(0),
            If(self.we & ~any_error,
                buf_just_written.eq(1),
                buf_pending.eq(1),
                buf.eq(self.ev)
            )
        ]
        self.comb += self.writable.eq(fifo.writable)

        # Buffer output of FIFO to improve timing
        dout_stb = Signal()
        dout_ack = Signal()
        dout = Record(ev_layout)
        self.sync.rio += \
            If(fifo.re,
                dout_stb.eq(1),
                dout.eq(fifo_out)
            ).Elif(dout_ack,
                dout_stb.eq(0)
            )
        self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

        # FIFO read through buffer
        self.comb += [
            dout_ack.eq(
                dout.timestamp[fine_ts_width:] == counter.value_rtio),
            interface.stb.eq(dout_stb & dout_ack)
        ]

        busy_transfer = _BlindTransfer()
        self.submodules += busy_transfer
        self.comb += [
            busy_transfer.i.eq(interface.stb & interface.busy),
            self.busy.eq(busy_transfer.o),
        ]

        if data_width:
            self.comb += interface.data.eq(dout.data)
        if address_width:
            self.comb += interface.address.eq(dout.address)
        if fine_ts_width:
            self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
Exemple #8
0
    def add_output(self, n, channel):
        rt_packet = self.rt_packet
        max_fine_ts_width = self.max_fine_ts_width

        interface = channel.interface.o
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)
        assert fine_ts_width <= max_fine_ts_width

        we = Signal()
        self.comb += we.eq(rt_packet.write_stb
                           & (rt_packet.write_channel == n))
        write_timestamp = rt_packet.write_timestamp[max_fine_ts_width -
                                                    fine_ts_width:]
        write_timestamp_coarse = rt_packet.write_timestamp[max_fine_ts_width:]
        write_timestamp_fine = rt_packet.write_timestamp[
            max_fine_ts_width - fine_ts_width:max_fine_ts_width]

        # latency compensation
        if interface.delay:
            tsc_comp = Signal.like(self.tsc)
            self.sync.rtio += tsc_comp.eq(self.tsc - interface.delay + 1)
        else:
            tsc_comp = self.tsc

        # FIFO
        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width))

        fifo = ClockDomainsRenamer("rio")(SyncFIFOBuffered(
            layout_len(ev_layout), channel.ofifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision = Signal()
        any_error = Signal()
        if interface.enable_replace:
            # Note: replace may be asserted at the same time as collision
            # when addresses are different. In that case, it is a collision.
            self.sync.rio += replace.eq(write_timestamp == buf.timestamp)
        # Detect sequence errors on coarse timestamps only
        # so that they are mutually exclusive with collision errors.
        self.sync.rio += sequence_error.eq(
            write_timestamp_coarse < buf.timestamp[fine_ts_width:])
        if interface.enable_replace:
            if address_width:
                different_addresses = rt_packet.write_address != buf.address
            else:
                different_addresses = 0
            if fine_ts_width:
                self.sync.rio += collision.eq(
                    (write_timestamp_coarse == buf.timestamp[fine_ts_width:])
                    & ((write_timestamp_fine != buf.timestamp[:fine_ts_width])
                       | different_addresses))
            else:
                self.sync.rio += collision.eq(
                    (write_timestamp == buf.timestamp) & different_addresses)
        else:
            self.sync.rio += collision.eq(
                write_timestamp_coarse == buf.timestamp[fine_ts_width:])
        self.comb += any_error.eq(sequence_error | collision)
        self.sync.rio += [
            If(we & sequence_error, self.write_sequence_error.eq(1)),
            If(we & collision, self.collision.eq(1))
        ]

        # Buffer read and FIFO write
        self.comb += fifo_in.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:] < tsc_comp + 4)
        self.sync.rio += If(in_guard_time, buf_pending.eq(0))
        report_underflow = Signal()
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        report_underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(we & ~replace & ~any_error,
                   fifo.we.eq(1)
                )
            )
        self.sync.rio += If(report_underflow, self.write_underflow.eq(1))

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rio += [
            buf_just_written.eq(0),
            If(
                we & ~any_error,
                buf_just_written.eq(1),
                buf_pending.eq(1),
                buf.timestamp.eq(write_timestamp),
                buf.data.eq(rt_packet.write_data) if data_width else [],
                buf.address.eq(rt_packet.write_address)
                if address_width else [],
            ),
            If(we & ~fifo.writable, self.write_overflow.eq(1))
        ]

        # FIFO level
        self.sync.rio += \
            If(rt_packet.fifo_space_update &
               (rt_packet.fifo_space_channel == n),
                rt_packet.fifo_space.eq(channel.ofifo_depth - fifo.level))

        # FIFO read
        self.sync.rio += [
            fifo.re.eq(0),
            interface.stb.eq(0),
            If(
                fifo.readable
                & (fifo_out.timestamp[fine_ts_width:] == tsc_comp),
                fifo.re.eq(1), interface.stb.eq(1))
        ]
        if data_width:
            self.sync.rio += interface.data.eq(fifo_out.data)
        if address_width:
            self.sync.rio += interface.address.eq(fifo_out.address)
        if fine_ts_width:
            self.sync.rio += interface.fine_ts.eq(
                fifo_out.timestamp[:fine_ts_width])

        self.sync.rio += If(interface.stb & interface.busy, self.busy.eq(1))
Exemple #9
0
    def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", counter.width + fine_ts_width))
        # ev must be valid 1 cycle before we to account for the latency in
        # generating replace, sequence_error and nop
        self.ev = Record(ev_layout)

        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2

        self.underflow = Signal()  # valid 1 cycle after we, pulsed
        self.sequence_error = Signal()
        self.collision_error = Signal()

        # # #

        # FIFO
        fifo = ClockDomainsRenamer({"write": "rsys", "read": "rio"})(
            AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision_error = Signal()
        any_error = Signal()
        nop = Signal()
        self.sync.rsys += [
            # Note: replace does not perform any RTLink address checks,
            # i.e. a write to a different address will be silently replaced
            # as well.
            replace.eq(self.ev.timestamp == buf.timestamp),
            # Detect sequence errors on coarse timestamps only
            # so that they are mutually exclusive with collision errors.
            sequence_error.eq(self.ev.timestamp[fine_ts_width:]
                              < buf.timestamp[fine_ts_width:])
        ]
        if fine_ts_width:
            self.sync.rsys += collision_error.eq(
                (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
                & (self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width]))
        self.comb += any_error.eq(sequence_error | collision_error)
        if interface.suppress_nop:
            # disable NOP at reset: do not suppress a first write with all 0s
            nop_en = Signal(reset=0)
            addresses_equal = [getattr(self.ev, a) == getattr(buf, a)
                               for a in ("data", "address")
                               if hasattr(self.ev, a)]
            if addresses_equal:
                self.sync.rsys += nop.eq(
                    nop_en & reduce(and_, addresses_equal))
            else:
                self.comb.eq(nop.eq(0))
            self.sync.rsys += [
                # buf now contains valid data. enable NOP.
                If(self.we & ~any_error, nop_en.eq(1)),
                # underflows cancel the write. allow it to be retried.
                If(self.underflow, nop_en.eq(0))
            ]
        self.comb += [
            self.sequence_error.eq(self.we & sequence_error),
            self.collision_error.eq(self.we & collision_error)
        ]

        # Buffer read and FIFO write
        self.comb += fifo_in.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:]
                < counter.value_sys + guard_io_cycles)
        self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        self.underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(self.we & ~replace & ~nop & ~any_error,
                   fifo.we.eq(1)
                )
            )

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rsys += [
            buf_just_written.eq(0),
            If(self.we & ~nop & ~any_error,
                buf_just_written.eq(1),
                buf_pending.eq(1),
                buf.eq(self.ev)
            )
        ]
        self.comb += self.writable.eq(fifo.writable)

        # Buffer output of FIFO to improve timing
        dout_stb = Signal()
        dout_ack = Signal()
        dout = Record(ev_layout)
        self.sync.rio += \
            If(fifo.re,
                dout_stb.eq(1),
                dout.eq(fifo_out)
            ).Elif(dout_ack,
                dout_stb.eq(0)
            )
        self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

        # FIFO read through buffer
        # TODO: report error on stb & busy
        self.comb += [
            dout_ack.eq(
                dout.timestamp[fine_ts_width:] == counter.value_rio),
            interface.stb.eq(dout_stb & dout_ack)
        ]
        if data_width:
            self.comb += interface.data.eq(dout.data)
        if address_width:
            self.comb += interface.address.eq(dout.address)
        if fine_ts_width:
            self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
Exemple #10
0
    def __init__(self, rt_packets, channels, max_fine_ts_width, full_ts_width):
        tsc = Signal(full_ts_width - max_fine_ts_width)
        self.sync.rtio += \
            If(rt_packets.tsc_load,
                tsc.eq(rt_packets.tsc_value)
            ).Else(
                tsc.eq(tsc + 1)
            )

        for n, channel in enumerate(channels):
            interface = channel.interface.o
            data_width = rtlink.get_data_width(interface)
            address_width = rtlink.get_address_width(interface)
            fine_ts_width = rtlink.get_fine_ts_width(interface)
            assert fine_ts_width <= max_fine_ts_width

            # FIFO
            ev_layout = []
            if data_width:
                ev_layout.append(("data", data_width))
            if address_width:
                ev_layout.append(("address", address_width))
            ev_layout.append(("timestamp", len(tsc) + fine_ts_width))

            fifo = ClockDomainsRenamer("rio")(SyncFIFOBuffered(
                layout_len(ev_layout), channel.ofifo_depth))
            self.submodules += fifo
            fifo_in = Record(ev_layout)
            fifo_out = Record(ev_layout)
            self.comb += [
                fifo.din.eq(fifo_in.raw_bits()),
                fifo_out.raw_bits().eq(fifo.dout)
            ]

            # FIFO level
            self.sync.rio += \
                If(rt_packets.fifo_space_update &
                   (rt_packets.fifo_space_channel == n),
                    rt_packets.fifo_space.eq(channel.ofifo_depth - fifo.level))

            # FIFO write
            self.comb += fifo.we.eq(rt_packets.write_stb
                                    & (rt_packets.write_channel == n))
            self.sync.rio += [
                If(rt_packets.write_overflow_ack,
                   rt_packets.write_overflow.eq(0)),
                If(rt_packets.write_underflow_ack,
                   rt_packets.write_underflow.eq(0)),
                If(
                    fifo.we, If(~fifo.writable,
                                rt_packets.write_overflow.eq(1)),
                    If(
                        rt_packets.write_timestamp[max_fine_ts_width:] <
                        (tsc + 4), rt_packets.write_underflow.eq(1)))
            ]
            if data_width:
                self.comb += fifo_in.data.eq(rt_packets.write_data)
            if address_width:
                self.comb += fifo_in.address.eq(rt_packets.write_address)
            self.comb += fifo_in.timestamp.eq(
                rt_packets.write_timestamp[max_fine_ts_width - fine_ts_width:])

            # FIFO read
            self.sync.rio += [
                fifo.re.eq(0),
                interface.stb.eq(0),
                If(fifo.readable & (fifo_out.timestamp[fine_ts_width:] == tsc),
                   fifo.re.eq(1), interface.stb.eq(1))
            ]
            if data_width:
                self.sync.rio += interface.data.eq(fifo_out.data)
            if address_width:
                self.sync.rio += interface.address.eq(fifo_out.address)
            if fine_ts_width:
                self.sync.rio += interface.fine_ts.eq(
                    fifo_out.timestamp[:fine_ts_width])
Exemple #11
0
    def __init__(self, channels, full_ts_width=63, guard_io_cycles=20):
        data_width = max(rtlink.get_data_width(c.interface) for c in channels)
        address_width = max(
            rtlink.get_address_width(c.interface) for c in channels)
        fine_ts_width = max(
            rtlink.get_fine_ts_width(c.interface) for c in channels)

        self.data_width = data_width
        self.address_width = address_width
        self.fine_ts_width = fine_ts_width

        # CSRs
        self.kcsrs = _KernelCSRs(bits_for(len(channels) - 1), data_width,
                                 address_width, full_ts_width)

        # Clocking/Reset
        # Create rsys, rio and rio_phy domains based on sys and rtio
        # with reset controlled by CSR.
        self.clock_domains.cd_rsys = ClockDomain()
        self.clock_domains.cd_rio = ClockDomain()
        self.clock_domains.cd_rio_phy = ClockDomain()
        self.comb += [
            self.cd_rsys.clk.eq(ClockSignal()),
            self.cd_rsys.rst.eq(self.kcsrs.reset.storage)
        ]
        self.comb += self.cd_rio.clk.eq(ClockSignal("rtio"))
        self.specials += AsyncResetSynchronizer(
            self.cd_rio, self.kcsrs.reset.storage
            | ResetSignal("rtio", allow_reset_less=True))
        self.comb += self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
        self.specials += AsyncResetSynchronizer(
            self.cd_rio_phy, self.kcsrs.reset_phy.storage
            | ResetSignal("rtio", allow_reset_less=True))

        # Managers
        self.submodules.counter = _RTIOCounter(full_ts_width - fine_ts_width)

        i_datas, i_timestamps = [], []
        o_statuses, i_statuses = [], []
        sel = self.kcsrs.chan_sel.storage
        for n, channel in enumerate(channels):
            if isinstance(channel, LogChannel):
                i_datas.append(0)
                i_timestamps.append(0)
                i_statuses.append(0)
                continue

            selected = Signal()
            self.comb += selected.eq(sel == n)

            o_manager = _OutputManager(channel.interface.o, self.counter,
                                       channel.ofifo_depth, guard_io_cycles)
            self.submodules += o_manager

            if hasattr(o_manager.ev, "data"):
                self.comb += o_manager.ev.data.eq(self.kcsrs.o_data.storage)
            if hasattr(o_manager.ev, "address"):
                self.comb += o_manager.ev.address.eq(
                    self.kcsrs.o_address.storage)
            ts_shift = (len(self.kcsrs.o_timestamp.storage) -
                        len(o_manager.ev.timestamp))
            self.comb += o_manager.ev.timestamp.eq(
                self.kcsrs.o_timestamp.storage[ts_shift:])

            self.comb += o_manager.we.eq(selected & self.kcsrs.o_we.re)

            underflow = Signal()
            sequence_error = Signal()
            collision = Signal()
            busy = Signal()
            self.sync.rsys += [
                If(selected & self.kcsrs.o_underflow_reset.re,
                   underflow.eq(0)),
                If(selected & self.kcsrs.o_sequence_error_reset.re,
                   sequence_error.eq(0)),
                If(selected & self.kcsrs.o_collision_reset.re,
                   collision.eq(0)),
                If(selected & self.kcsrs.o_busy_reset.re, busy.eq(0)),
                If(o_manager.underflow, underflow.eq(1)),
                If(o_manager.sequence_error, sequence_error.eq(1)),
                If(o_manager.collision, collision.eq(1)),
                If(o_manager.busy, busy.eq(1))
            ]
            o_statuses.append(
                Cat(~o_manager.writable, underflow, sequence_error, collision,
                    busy))

            if channel.interface.i is not None:
                i_manager = _InputManager(channel.interface.i, self.counter,
                                          channel.ififo_depth)
                self.submodules += i_manager

                if hasattr(i_manager.ev, "data"):
                    i_datas.append(i_manager.ev.data)
                else:
                    i_datas.append(0)
                if channel.interface.i.timestamped:
                    ts_shift = (len(self.kcsrs.i_timestamp.status) -
                                len(i_manager.ev.timestamp))
                    i_timestamps.append(i_manager.ev.timestamp << ts_shift)
                else:
                    i_timestamps.append(0)

                self.comb += i_manager.re.eq(selected & self.kcsrs.i_re.re)

                overflow = Signal()
                self.sync.rsys += [
                    If(selected & self.kcsrs.i_overflow_reset.re,
                       overflow.eq(0)),
                    If(i_manager.overflow, overflow.eq(1))
                ]
                i_statuses.append(Cat(~i_manager.readable, overflow))

            else:
                i_datas.append(0)
                i_timestamps.append(0)
                i_statuses.append(0)
        if data_width:
            self.comb += self.kcsrs.i_data.status.eq(Array(i_datas)[sel])
        self.comb += [
            self.kcsrs.i_timestamp.status.eq(Array(i_timestamps)[sel]),
            self.kcsrs.o_status.status.eq(Array(o_statuses)[sel]),
            self.kcsrs.i_status.status.eq(Array(i_statuses)[sel])
        ]

        # Counter access
        self.sync += \
           If(self.kcsrs.counter_update.re,
               self.kcsrs.counter.status.eq(self.counter.value_sys
                                                << fine_ts_width)
           )
Exemple #12
0
    def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", counter.width + fine_ts_width))
        # ev must be valid 1 cycle before we to account for the latency in
        # generating replace, sequence_error and nop
        self.ev = Record(ev_layout)

        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2

        self.underflow = Signal()  # valid 1 cycle after we, pulsed
        self.sequence_error = Signal()
        self.collision_error = Signal()

        # # #

        # FIFO
        fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth), {
            "write": "rsys",
            "read": "rio"
        })
        self.submodules += fifo

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision_error = Signal()
        any_error = Signal()
        nop = Signal()
        self.sync.rsys += [
            # Note: replace does not perform any RTLink address checks,
            # i.e. a write to a different address will be silently replaced
            # as well.
            replace.eq(self.ev.timestamp == buf.timestamp),
            # Detect sequence errors on coarse timestamps only
            # so that they are mutually exclusive with collision errors.
            sequence_error.eq(self.ev.timestamp[fine_ts_width:] <
                              buf.timestamp[fine_ts_width:])
        ]
        if fine_ts_width:
            self.sync.rsys += collision_error.eq(
                (self.ev.timestamp[fine_ts_width:] ==
                 buf.timestamp[fine_ts_width:])
                & (self.ev.timestamp[:fine_ts_width] !=
                   buf.timestamp[:fine_ts_width]))
        self.comb += any_error.eq(sequence_error | collision_error)
        if interface.suppress_nop:
            # disable NOP at reset: do not suppress a first write with all 0s
            nop_en = Signal(reset=0)
            self.sync.rsys += [
                nop.eq(nop_en & optree("&", [
                    getattr(self.ev, a) == getattr(buf, a)
                    for a in ("data", "address") if hasattr(self.ev, a)
                ],
                                       default=0)),
                # buf now contains valid data. enable NOP.
                If(self.we & ~any_error, nop_en.eq(1)),
                # underflows cancel the write. allow it to be retried.
                If(self.underflow, nop_en.eq(0))
            ]
        self.comb += [
            self.sequence_error.eq(self.we & sequence_error),
            self.collision_error.eq(self.we & collision_error)
        ]

        # Buffer read and FIFO write
        self.comb += fifo.din.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:] < counter.value_sys +
            guard_io_cycles)
        self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        self.underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(self.we & ~replace & ~nop & ~any_error,
                   fifo.we.eq(1)
                )
            )

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rsys += [
            buf_just_written.eq(0),
            If(self.we & ~nop & ~any_error, buf_just_written.eq(1),
               buf_pending.eq(1), buf.eq(self.ev))
        ]
        self.comb += self.writable.eq(fifo.writable)

        # Buffer output of FIFO to improve timing
        dout_stb = Signal()
        dout_ack = Signal()
        dout = Record(ev_layout)
        self.sync.rio += \
            If(fifo.re,
                dout_stb.eq(1),
                dout.eq(fifo.dout)
            ).Elif(dout_ack,
                dout_stb.eq(0)
            )
        self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

        # FIFO read through buffer
        # TODO: report error on stb & busy
        self.comb += [
            dout_ack.eq(dout.timestamp[fine_ts_width:] == counter.value_rio),
            interface.stb.eq(dout_stb & dout_ack)
        ]
        if data_width:
            self.comb += interface.data.eq(dout.data)
        if address_width:
            self.comb += interface.address.eq(dout.address)
        if fine_ts_width:
            self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
Exemple #13
0
    def add_output(self, n, channel):
        rt_packet = self.rt_packet
        max_fine_ts_width = self.max_fine_ts_width

        interface = channel.interface.o
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)
        assert fine_ts_width <= max_fine_ts_width

        we = Signal()
        self.comb += we.eq(rt_packet.write_stb
                           & (rt_packet.write_channel == n))
        write_timestamp = rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:]
        write_timestamp_coarse = rt_packet.write_timestamp[max_fine_ts_width:]
        write_timestamp_fine = rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:max_fine_ts_width]

        # latency compensation
        if interface.delay:
            tsc_comp = Signal.like(self.tsc)
            self.sync.rtio += tsc_comp.eq(self.tsc - interface.delay + 1)
        else:
            tsc_comp = self.tsc

        # FIFO
        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width))

        fifo = ClockDomainsRenamer("rio")(
            SyncFIFOBuffered(layout_len(ev_layout), channel.ofifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision = Signal()
        any_error = Signal()
        if interface.enable_replace:
            # Note: replace may be asserted at the same time as collision
            # when addresses are different. In that case, it is a collision.
            self.sync.rio += replace.eq(write_timestamp == buf.timestamp)
        # Detect sequence errors on coarse timestamps only
        # so that they are mutually exclusive with collision errors.
        self.sync.rio += sequence_error.eq(write_timestamp_coarse < buf.timestamp[fine_ts_width:])
        if interface.enable_replace:
            if address_width:
                different_addresses = rt_packet.write_address != buf.address
            else:
                different_addresses = 0
            if fine_ts_width:
                self.sync.rio += collision.eq(
                    (write_timestamp_coarse == buf.timestamp[fine_ts_width:])
                    & ((write_timestamp_fine != buf.timestamp[:fine_ts_width])
                       |different_addresses))
            else:
                self.sync.rio += collision.eq(
                    (write_timestamp == buf.timestamp) & different_addresses)
        else:
            self.sync.rio += collision.eq(
                write_timestamp_coarse == buf.timestamp[fine_ts_width:])
        self.comb += any_error.eq(sequence_error | collision)
        self.sync.rio += [
            If(we & sequence_error, self.write_sequence_error.eq(1)),
            If(we & collision, self.collision.eq(1))
        ]

        # Buffer read and FIFO write
        self.comb += fifo_in.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:] < tsc_comp + 4)
        self.sync.rio += If(in_guard_time, buf_pending.eq(0))
        report_underflow = Signal()
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        report_underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(we & ~replace & ~any_error,
                   fifo.we.eq(1)
                )
            )
        self.sync.rio += If(report_underflow, self.write_underflow.eq(1))

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rio += [
            buf_just_written.eq(0),
            If(we & ~any_error,
                buf_just_written.eq(1),
                buf_pending.eq(1),
                buf.timestamp.eq(write_timestamp),
                buf.data.eq(rt_packet.write_data) if data_width else [],
                buf.address.eq(rt_packet.write_address) if address_width else [],
            ),
            If(we & ~fifo.writable, self.write_overflow.eq(1))
        ]

        # FIFO level
        self.sync.rio += \
            If(rt_packet.fifo_space_update &
               (rt_packet.fifo_space_channel == n),
                rt_packet.fifo_space.eq(channel.ofifo_depth - fifo.level))

        # FIFO read
        self.sync.rio += [
            fifo.re.eq(0),
            interface.stb.eq(0),
            If(fifo.readable &
               (fifo_out.timestamp[fine_ts_width:] == tsc_comp),
                fifo.re.eq(1),
                interface.stb.eq(1)
            )
        ]
        if data_width:
            self.sync.rio += interface.data.eq(fifo_out.data)
        if address_width:
            self.sync.rio += interface.address.eq(fifo_out.address)
        if fine_ts_width:
            self.sync.rio += interface.fine_ts.eq(fifo_out.timestamp[:fine_ts_width])

        self.sync.rio += If(interface.stb & interface.busy, self.busy.eq(1))