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] )
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") )
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])
def __init__(self, **kwargs): self.submodules.fifo = SyncFIFOBuffered(width=8, depth=64) self.submodules.dut = EventAnalyzer(self.fifo, **kwargs)