Ejemplo n.º 1
0
    def __init__(self, endpoint, port, table_depth=256):
        self.port   = port
        self.sink   = sink = stream.Endpoint(dma_layout(endpoint.phy.data_width))
        self.irq    = Signal()
        self.enable = CSRStorage(description="DMA Writer Control. Write ``1`` to enable DMA Writer.")

        # # #

        counter = Signal(max=(2**len(endpoint.phy.max_payload_size))//8)

        # CSR/Parameters ---------------------------------------------------------------------------
        enable = self.enable.storage

        max_words_per_request = max_payload_size//(endpoint.phy.data_width//8)
        fifo_depth            = 4*max_words_per_request

        # Table/Splitter ---------------------------------------------------------------------------
        # Descriptors from table are splitted in descriptors of max_payload_size (negotiated at link-up)
        table    = LitePCIeDMAScatterGather(table_depth)
        splitter = LitePCIeDMADescriptorSplitter(max_size=endpoint.phy.max_payload_size)
        splitter = ResetInserter()(splitter)
        splitter = BufferizeEndpoints({"source": DIR_SOURCE})(splitter)
        self.submodules.table    = table
        self.submodules.splitter = splitter
        self.comb += [
            splitter.reset.eq(~enable),
            table.source.connect(splitter.sink)
        ]

        # Data FIFO --------------------------------------------------------------------------------
        fifo = SyncFIFOBuffered(endpoint.phy.data_width + 1, fifo_depth)
        self.submodules += ResetInserter()(fifo)
        self.comb += [
            fifo.we.eq(sink.valid & enable),
            sink.ready.eq(fifo.writable | ~enable),
            fifo.din.eq(Cat(sink.data, sink.last)),
            fifo.reset.eq(~enable)
        ]

        # FSM --------------------------------------------------------------------------------------
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act("IDLE",
            NextValue(counter, 0),
            If(splitter.source.valid,
                If(fifo.level >= splitter.source.length[log2_int(endpoint.phy.data_width//8):],
                    NextState("REQUEST"),
                )
            )
        )
        length_shift = log2_int(endpoint.phy.data_width//8)
        self.comb += [
            port.source.channel.eq(port.channel),
            port.source.user_id.eq(splitter.source.user_id),
            port.source.first.eq(counter == 0),
            port.source.last.eq(~enable | (counter == splitter.source.length[length_shift:] - 1)),
            port.source.we.eq(1),
            port.source.adr.eq(splitter.source.address),
            port.source.req_id.eq(endpoint.phy.id),
            port.source.tag.eq(0),
            port.source.len.eq(splitter.source.length[2:]),
            port.source.dat.eq(fifo.dout[:-1])
        ]
        fsm.act("REQUEST",
            port.source.valid.eq(1),
            If(port.source.ready,
                NextValue(counter, counter + 1),
                # read only if not last
                fifo.re.eq(~(fifo.dout[-1] & ~splitter.source.control[DMA_LAST_DISABLE])),
                If(port.source.last,
                    # always read
                    fifo.re.eq(1),
                    splitter.end.eq(fifo.dout[-1] & ~splitter.source.control[DMA_LAST_DISABLE]),
                    splitter.source.ready.eq(1),
                    NextState("IDLE"),
                )
            )
        )

        # IRQ --------------------------------------------------------------------------------------
        self.comb += self.irq.eq(
            splitter.source.valid &
            splitter.source.ready &
            splitter.source.last  &
            ~splitter.source.control[DMA_IRQ_DISABLE]
        )
Ejemplo n.º 2
0
    def do_finalize(self):
        assert len(self.event_sources) < 2 ** 6
        assert max(s.width for s in self.event_sources) <= 32

        # Fill the event, event data, and delay FIFOs.
        throttle_on    = Signal()
        throttle_off   = Signal()
        throttle_edge  = Signal()
        throttle_fifos = []
        self.sync += [
            If(~self.throttle & throttle_on,
                self.throttle.eq(1),
                throttle_edge.eq(1)
            ).Elif(self.throttle & throttle_off,
                self.throttle.eq(0),
                throttle_edge.eq(1)
            ).Else(
                throttle_edge.eq(0)
            )
        ]

        overrun_trip   = Signal()
        overrun_fifos  = []
        self.sync += [
            If(overrun_trip,
                self.overrun.eq(1)
            )
        ]

        event_width = 1 + len(self.event_sources)
        if self.event_depth is None:
            event_depth = min(self._depth_for_width(event_width),
                              self._depth_for_width(self.delay_width))
        else:
            event_depth = self.event_depth

        self.submodules.event_fifo = event_fifo = \
            SyncFIFOBuffered(width=event_width, depth=event_depth)
        throttle_fifos.append(self.event_fifo)
        self.comb += [
            event_fifo.din.eq(Cat(self.throttle, [s.trigger for s in self.event_sources])),
            event_fifo.we.eq(reduce(lambda a, b: a | b, (s.trigger for s in self.event_sources)) |
                             throttle_edge)
        ]

        self.submodules.delay_fifo = delay_fifo = \
            SyncFIFOBuffered(width=self.delay_width, depth=event_depth)
        delay_timer = self._delay_timer = Signal(self.delay_width)
        delay_ovrun = ((1 << self.delay_width) - 1)
        delay_max   = delay_ovrun - 1
        self.sync += [
            If(delay_fifo.we,
                delay_timer.eq(0)
            ).Else(
                delay_timer.eq(delay_timer + 1)
            )
        ]
        self.comb += [
            delay_fifo.din.eq(Mux(self.overrun, delay_ovrun, delay_timer)),
            delay_fifo.we.eq(event_fifo.we | (delay_timer == delay_max) |
                             self.done | self.overrun),
        ]

        for event_source in self.event_sources:
            if event_source.width > 0:
                event_source.submodules.data_fifo = event_data_fifo = \
                    SyncFIFOBuffered(event_source.width, event_source.depth)
                self.submodules += event_source
                throttle_fifos.append(event_data_fifo)
                self.comb += [
                    event_data_fifo.din.eq(event_source.data),
                    event_data_fifo.we.eq(event_source.trigger),
                ]
            else:
                event_source.submodules.data_fifo = _FIFOInterface(1, 0)

        # Throttle applets based on FIFO levels with hysteresis.
        self.comb += [
            throttle_on .eq(reduce(lambda a, b: a | b,
                (f.fifo.level >= f.depth - f.depth // (4 if f.depth > 4 else 2)
                 for f in throttle_fifos))),
            throttle_off.eq(reduce(lambda a, b: a & b,
                (f.fifo.level <            f.depth // (4 if f.depth > 4 else 2)
                 for f in throttle_fifos))),
        ]

        # Detect imminent FIFO overrun and trip overrun indication.
        self.comb += [
            overrun_trip.eq(reduce(lambda a, b: a | b,
                (f.fifo.level == f.depth - 2
                 for f in throttle_fifos)))
        ]

        # Dequeue events, and serialize events and event data.
        self.submodules.event_encoder = event_encoder = \
            PriorityEncoder(width=len(self.event_sources))
        self.submodules.event_decoder = event_decoder = \
            PriorityDecoder(width=len(self.event_sources))
        self.comb += event_decoder.i.eq(event_encoder.o)

        self.submodules.serializer = serializer = FSM(reset_state="WAIT-EVENT")
        rep_overrun      = Signal()
        rep_throttle_new = Signal()
        rep_throttle_cur = Signal()
        delay_septets = 5
        delay_counter = Signal(7 * delay_septets)
        serializer.act("WAIT-EVENT",
            If(delay_fifo.readable,
                delay_fifo.re.eq(1),
                NextValue(delay_counter, delay_counter + delay_fifo.dout + 1),
                If(delay_fifo.dout == delay_ovrun,
                    NextValue(rep_overrun, 1),
                    NextState("REPORT-DELAY")
                )
            ),
            If(event_fifo.readable,
                event_fifo.re.eq(1),
                NextValue(event_encoder.i, event_fifo.dout[1:]),
                NextValue(rep_throttle_new, event_fifo.dout[0]),
                If((event_fifo.dout != 0) | (rep_throttle_cur != event_fifo.dout[0]),
                    NextState("REPORT-DELAY")
                )
            ).Elif(self.done,
                NextState("REPORT-DELAY")
            )
        )
        serializer.act("REPORT-DELAY",
            If(delay_counter >= 128 ** 4,
                NextState("REPORT-DELAY-5")
            ).Elif(delay_counter >= 128 ** 3,
                NextState("REPORT-DELAY-4")
            ).Elif(delay_counter >= 128 ** 2,
                NextState("REPORT-DELAY-3")
            ).Elif(delay_counter >= 128 ** 1,
                NextState("REPORT-DELAY-2")
            ).Else(
                NextState("REPORT-DELAY-1")
            )
        )
        for septet_no in range(delay_septets, 0, -1):
            if septet_no == 1:
                next_state = [
                    NextValue(delay_counter, 0),
                    If(rep_overrun,
                        NextState("REPORT-OVERRUN")
                    ).Elif(rep_throttle_cur != rep_throttle_new,
                        NextState("REPORT-THROTTLE")
                    ).Elif(event_encoder.i,
                        NextState("REPORT-EVENT")
                    ).Elif(self.done,
                        NextState("REPORT-DONE")
                    ).Else(
                        NextState("WAIT-EVENT")
                    )
                ]
            else:
                next_state = [
                    NextState("REPORT-DELAY-%d" % (septet_no - 1))
                ]
            serializer.act("REPORT-DELAY-%d" % septet_no,
                If(self.output_fifo.writable,
                    self.output_fifo.din.eq(
                        REPORT_DELAY | delay_counter.part((septet_no - 1) * 7, 7)),
                    self.output_fifo.we.eq(1),
                    *next_state
                )
            )
        serializer.act("REPORT-THROTTLE",
            If(self.output_fifo.writable,
                NextValue(rep_throttle_cur, rep_throttle_new),
                If(rep_throttle_new,
                    self.output_fifo.din.eq(REPORT_SPECIAL | SPECIAL_THROTTLE),
                ).Else(
                    self.output_fifo.din.eq(REPORT_SPECIAL | SPECIAL_DETHROTTLE),
                ),
                self.output_fifo.we.eq(1),
                If(event_encoder.n,
                    NextState("WAIT-EVENT")
                ).Else(
                    NextState("REPORT-EVENT")
                )
            )
        )
        event_source = self.event_sources[event_encoder.o]
        event_data   = Signal(32)
        serializer.act("REPORT-EVENT",
            If(self.output_fifo.writable,
                NextValue(event_encoder.i, event_encoder.i & ~event_decoder.o),
                self.output_fifo.din.eq(
                    REPORT_EVENT | event_encoder.o),
                self.output_fifo.we.eq(1),
                NextValue(event_data, event_source.data_fifo.dout),
                event_source.data_fifo.re.eq(1),
                If(event_source.width > 24,
                    NextState("REPORT-EVENT-DATA-4")
                ).Elif(event_source.width > 16,
                    NextState("REPORT-EVENT-DATA-3")
                ).Elif(event_source.width > 8,
                    NextState("REPORT-EVENT-DATA-2")
                ).Elif(event_source.width > 0,
                    NextState("REPORT-EVENT-DATA-1")
                ).Else(
                    If(event_encoder.i & ~event_decoder.o,
                        NextState("REPORT-EVENT")
                    ).Else(
                        NextState("WAIT-EVENT")
                    )
                )
            )
        )
        for octet_no in range(4, 0, -1):
            if octet_no == 1:
                next_state = [
                    If(event_encoder.n,
                        NextState("WAIT-EVENT")
                    ).Else(
                        NextState("REPORT-EVENT")
                    )
                ]
            else:
                next_state = [
                    NextState("REPORT-EVENT-DATA-%d" % (octet_no - 1))
                ]
            serializer.act("REPORT-EVENT-DATA-%d" % octet_no,
                If(self.output_fifo.writable,
                    self.output_fifo.din.eq(event_data.part((octet_no - 1) * 8, 8)),
                    self.output_fifo.we.eq(1),
                    *next_state
                )
            )
            serializer.act("REPORT-DONE",
                If(self.output_fifo.writable,
                    self.output_fifo.din.eq(REPORT_SPECIAL | SPECIAL_DONE),
                    self.output_fifo.we.eq(1),
                    NextState("DONE")
                )
            )
            serializer.act("DONE",
                If(~self.done,
                    NextState("WAIT-EVENT")
                )
            )
            serializer.act("REPORT-OVERRUN",
                If(self.output_fifo.writable,
                    self.output_fifo.din.eq(REPORT_SPECIAL | SPECIAL_OVERRUN),
                    self.output_fifo.we.eq(1),
                    NextState("OVERRUN")
                )
            )
            serializer.act("OVERRUN",
                NextState("OVERRUN")
            )
Ejemplo n.º 3
0
    def __init__(self, endpoint, port, table_depth=256):
        self.sink = sink = stream.Endpoint(dma_layout(endpoint.phy.data_width))
        self.irq = Signal()
        self.enable = CSRStorage()

        # # #

        enable = self.enable.storage

        max_words_per_request = max_request_size // (endpoint.phy.data_width //
                                                     8)
        fifo_depth = 4 * max_words_per_request

        # Data FIFO

        # store data until we have enough data to issue a write request
        fifo = SyncFIFOBuffered(endpoint.phy.data_width + 1, fifo_depth)
        self.submodules += ResetInserter()(fifo)
        self.comb += [
            fifo.we.eq(sink.valid & enable),
            sink.ready.eq(fifo.writable & enable),
            fifo.din.eq(Cat(sink.data, sink.last)),
            fifo.reset.eq(~enable)
        ]

        # Request generation
        request_ready = Signal()
        counter = Signal(max=(2**len(endpoint.phy.max_payload_size)) // 8)
        counter_reset = Signal()
        counter_ce = Signal()
        self.sync += \
            If(counter_reset,
                counter.eq(0)
            ).Elif(counter_ce,
                counter.eq(counter + 1)
            )

        # requests from table are splitted in chunks of "max_size"
        self.table = table = LitePCIeDMARequestTable(table_depth)
        splitter = LitePCIeDMARequestSplitter(endpoint.phy.max_payload_size)
        self.submodules += table, BufferizeEndpoints({"source": DIR_SOURCE})(
            ResetInserter()(splitter))
        self.comb += [
            splitter.reset.eq(~enable),
            table.source.connect(splitter.sink)
        ]

        # Request FSM
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act("IDLE", counter_reset.eq(1),
                If(
                    request_ready,
                    NextState("REQUEST"),
                ))
        self.comb += [
            port.source.channel.eq(port.channel),
            port.source.user_id.eq(splitter.source.user_id),
            port.source.first.eq(counter == 0),
            port.source.last.eq((counter == splitter.source.length[3:] - 1)),
            port.source.we.eq(1),
            port.source.adr.eq(splitter.source.address),
            port.source.req_id.eq(endpoint.phy.id),
            port.source.tag.eq(0),
            port.source.len.eq(splitter.source.length[2:]),
            port.source.dat.eq(fifo.dout[:-1])
        ]
        fsm.act(
            "REQUEST",
            counter_ce.eq(port.source.valid & port.source.ready),
            port.source.valid.eq(1),
            If(
                port.source.ready,
                # read only if not last
                fifo.re.eq(~(fifo.dout[-1] & ~splitter.source.control[1])),
                If(
                    port.source.last,
                    # always read
                    fifo.re.eq(1),
                    splitter.end.eq(fifo.dout[-1]
                                    & ~splitter.source.control[1]),
                    splitter.source.ready.eq(1),
                    NextState("IDLE"),
                )))

        fifo_ready = fifo.level >= splitter.source.length[3:]
        self.sync += request_ready.eq(splitter.source.valid & fifo_ready)

        # IRQ
        self.comb += self.irq.eq(splitter.source.valid & splitter.source.ready
                                 & splitter.source.last
                                 & ~splitter.source.control[0])
Ejemplo n.º 4
0
 def __init__(self, **kwargs):
     self.submodules.fifo = SyncFIFOBuffered(width=8, depth=64)
     self.submodules.dut  = EventAnalyzer(self.fifo, **kwargs)