From: Florent Kermarrec Date: Wed, 21 Jan 2015 22:11:38 +0000 (+0100) Subject: add PacketBuffer, simplify architecture and reduce ressource usage X-Git-Tag: 24jan2021_ls180~2572^2~31 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ff0c8e3d2231ca79a18f6dcd8e5612fd35a374a8;p=litex.git add PacketBuffer, simplify architecture and reduce ressource usage --- diff --git a/litesata/__init__.py b/litesata/__init__.py index c75fc32c..78c3a8ca 100644 --- a/litesata/__init__.py +++ b/litesata/__init__.py @@ -6,14 +6,14 @@ from litesata.frontend import * from migen.bank.description import * class LiteSATA(Module, AutoCSR): - def __init__(self, phy, + def __init__(self, phy, buffer_depth=2*fis_max_dwords, with_crossbar=False, with_bist=False, with_bist_csr=False): # phy self.phy = phy # core - self.core = LiteSATACore(self.phy) + self.core = LiteSATACore(self.phy, buffer_depth) # frontend if with_crossbar: diff --git a/litesata/common.py b/litesata/common.py index 87d77edb..235c9065 100644 --- a/litesata/common.py +++ b/litesata/common.py @@ -301,3 +301,79 @@ class BufferizeEndpoints(Module): def __dir__(self): return dir(self.submodule) + +class EndpointPacketStatus(Module): + def __init__(self, endpoint): + self.start = Signal() + self.done = Signal() + self.ongoing = Signal() + + ongoing = Signal() + self.comb += [ + self.start.eq(endpoint.stb & endpoint.sop & endpoint.ack), + self.done.eq(endpoint.stb & endpoint.eop & endpoint.ack) + ] + self.sync += \ + If(self.start, + ongoing.eq(1) + ).Elif(self.done, + ongoing.eq(0) + ) + self.comb += self.ongoing.eq((self.start | ongoing) & ~self.done) + +class PacketBuffer(Module): + def __init__(self, description, data_depth, cmd_depth=4, almost_full=None): + self.sink = sink = Sink(description) + self.source = source = Source(description) + + ### + sink_status = EndpointPacketStatus(self.sink) + source_status = EndpointPacketStatus(self.source) + self.submodules += sink_status, source_status + + # store incoming packets + # cmds + def cmd_description(): + layout = [("error", 1)] + return EndpointDescription(layout) + self.cmd_fifo = cmd_fifo = SyncFIFO(cmd_description(), cmd_depth) + self.comb += [ + cmd_fifo.sink.stb.eq(sink_status.done), + cmd_fifo.sink.error.eq(sink.error) + ] + + # data + self.data_fifo = data_fifo = SyncFIFO(description, data_depth, buffered=True) + self.comb += [ + Record.connect(self.sink, data_fifo.sink), + data_fifo.sink.stb.eq(self.sink.stb & cmd_fifo.sink.ack), + self.sink.ack.eq(data_fifo.sink.ack & cmd_fifo.sink.ack), + ] + + # output packets + self.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + If(cmd_fifo.source.stb, + NextState("SEEK_SOP") + ) + ) + fsm.act("SEEK_SOP", + If(~data_fifo.source.sop, + data_fifo.source.ack.eq(1) + ).Else( + NextState("OUTPUT") + ) + ) + fsm.act("OUTPUT", + Record.connect(data_fifo.source, self.source), + self.source.error.eq(cmd_fifo.source.error), + If(source_status.done, + cmd_fifo.source.ack.eq(1), + NextState("IDLE") + ) + ) + + # compute almost full + if almost_full is not None: + self.almost_full = Signal() + self.comb += self.almost_full.eq(data_fifo.fifo.level > almost_full) diff --git a/litesata/core/__init__.py b/litesata/core/__init__.py index c32028bb..ce7dc903 100644 --- a/litesata/core/__init__.py +++ b/litesata/core/__init__.py @@ -4,8 +4,8 @@ from litesata.core.transport import LiteSATATransport from litesata.core.command import LiteSATACommand class LiteSATACore(Module): - def __init__(self, phy): - self.link = LiteSATALink(phy) + def __init__(self, phy, buffer_depth): + self.link = LiteSATALink(phy, buffer_depth) self.transport = LiteSATATransport(self.link) self.command = LiteSATACommand(self.transport) self.sink, self.source = self.command.sink, self.command.source diff --git a/litesata/core/command/__init__.py b/litesata/core/command/__init__.py index 3e0b9b79..f614415b 100644 --- a/litesata/core/command/__init__.py +++ b/litesata/core/command/__init__.py @@ -62,6 +62,7 @@ class LiteSATACommandTX(Module): If(is_write, NextState("WAIT_DMA_ACTIVATE") ).Else( + sink.ack.eq(1), NextState("IDLE") ) ) @@ -121,11 +122,6 @@ class LiteSATACommandRX(Module): ### - cmd_buffer = Buffer(command_rx_cmd_description(32)) - cmd_buffer.sink, cmd_buffer.source = cmd_buffer.d, cmd_buffer.q - data_buffer = InsertReset(SyncFIFO(command_rx_data_description(32), fis_max_dwords, buffered=True)) - self.submodules += cmd_buffer, data_buffer - def test_type(name): return transport.source.type == fis_types[name] @@ -151,11 +147,22 @@ class LiteSATACommandRX(Module): d2h_error.eq(1) ) + read_error = Signal() + clr_read_error = Signal() + set_read_error = Signal() + self.sync += \ + If(clr_read_error, + read_error.eq(0) + ).Elif(set_read_error, + read_error.eq(1) + ) + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", self.dwords_counter.reset.eq(1), transport.source.ack.eq(1), clr_d2h_error.eq(1), + clr_read_error.eq(1), If(from_tx.write, NextState("WAIT_WRITE_ACTIVATE_OR_REG_D2H") ).Elif(from_tx.read, @@ -180,12 +187,14 @@ class LiteSATACommandRX(Module): ) ) fsm.act("PRESENT_WRITE_RESPONSE", - cmd_buffer.sink.stb.eq(1), - cmd_buffer.sink.write.eq(1), - cmd_buffer.sink.last.eq(1), - cmd_buffer.sink.success.eq(~transport.source.error & ~d2h_error), - cmd_buffer.sink.failed.eq(transport.source.error | d2h_error), - If(cmd_buffer.sink.stb & cmd_buffer.sink.ack, + source.stb.eq(1), + source.sop.eq(1), + source.eop.eq(1), + source.write.eq(1), + source.last.eq(1), + source.success.eq(~transport.source.error & ~d2h_error), + source.failed.eq(transport.source.error | d2h_error), + If(source.stb & source.ack, NextState("IDLE") ) ) @@ -196,7 +205,6 @@ class LiteSATACommandRX(Module): If(test_type("DATA"), NextState("PRESENT_READ_DATA") ).Elif(test_type("REG_D2H"), - set_d2h_error.eq(transport.source.status[reg_d2h_status["err"]]), NextState("PRESENT_READ_RESPONSE") ) ) @@ -217,90 +225,39 @@ class LiteSATACommandRX(Module): ) ) - self.comb += [ - data_buffer.sink.sop.eq(transport.source.sop), - data_buffer.sink.eop.eq(transport.source.eop), - data_buffer.sink.data.eq(transport.source.data) - ] fsm.act("PRESENT_READ_DATA", - data_buffer.sink.stb.eq(transport.source.stb), - transport.source.ack.eq(data_buffer.sink.ack), - If(data_buffer.sink.stb & data_buffer.sink.ack, + set_read_error.eq(transport.source.error), + source.stb.eq(transport.source.stb), + source.sop.eq(transport.source.sop), + source.eop.eq(transport.source.eop), + source.read.eq(~is_identify), + source.identify.eq(is_identify), + source.success.eq(~transport.source.error), + source.failed.eq(transport.source.error), + source.last.eq(is_identify), + source.data.eq(transport.source.data), + transport.source.ack.eq(source.ack), + If(source.stb & source.ack, self.dwords_counter.ce.eq(~read_done), - If(data_buffer.sink.eop, - If(read_done & ~is_identify, - NextState("WAIT_READ_DATA_OR_REG_D2H") + If(source.eop, + If(is_identify, + NextState("IDLE") ).Else( - NextState("PRESENT_READ_RESPONSE") + NextState("WAIT_READ_DATA_OR_REG_D2H") ) ) ) ) - read_error = Signal() - self.sync += \ - If(fsm.before_entering("PRESENT_READ_DATA"), - read_error.eq(1) - ).Elif(transport.source.stb & transport.source.ack & transport.source.eop, - read_error.eq(transport.source.error) - ) - fsm.act("PRESENT_READ_RESPONSE", - cmd_buffer.sink.stb.eq(1), - cmd_buffer.sink.read.eq(~is_identify), - cmd_buffer.sink.identify.eq(is_identify), - cmd_buffer.sink.last.eq(read_done | is_identify), - cmd_buffer.sink.success.eq(~read_error & ~d2h_error), - cmd_buffer.sink.failed.eq(read_error | d2h_error), - If(cmd_buffer.sink.stb & cmd_buffer.sink.ack, - If(cmd_buffer.sink.failed, - data_buffer.reset.eq(1) - ), - If(read_done | is_identify, - NextState("IDLE") - ).Else( - NextState("WAIT_READ_DATA_OR_REG_D2H") - ) - ) - ) - - self.out_fsm = out_fsm = FSM(reset_state="IDLE") - out_fsm.act("IDLE", - If(cmd_buffer.source.stb, - If((cmd_buffer.source.read | cmd_buffer.source.identify) & cmd_buffer.source.success, - NextState("PRESENT_RESPONSE_WITH_DATA"), - ).Else( - NextState("PRESENT_RESPONSE_WITHOUT_DATA"), - ) - ) - ) - - self.comb += [ - source.write.eq(cmd_buffer.source.write), - source.read.eq(cmd_buffer.source.read), - source.identify.eq(cmd_buffer.source.identify), - source.last.eq(cmd_buffer.source.last), - source.success.eq(cmd_buffer.source.success), - source.failed.eq(cmd_buffer.source.failed), - source.data.eq(data_buffer.source.data) - ] - - out_fsm.act("PRESENT_RESPONSE_WITH_DATA", - source.stb.eq(data_buffer.source.stb), - source.sop.eq(data_buffer.source.sop), - source.eop.eq(data_buffer.source.eop), - data_buffer.source.ack.eq(source.ack), - - If(source.stb & source.eop & source.ack, - cmd_buffer.source.ack.eq(1), - NextState("IDLE") - ) - ) - out_fsm.act("PRESENT_RESPONSE_WITHOUT_DATA", + fsm.act("PRESENT_READ_RESPONSE", source.stb.eq(1), source.sop.eq(1), source.eop.eq(1), + source.read.eq(1), + source.last.eq(1), + source.success.eq(read_done & ~read_error & ~d2h_error), + source.failed.eq(~read_done | read_error | d2h_error), If(source.stb & source.ack, - cmd_buffer.source.ack.eq(1), NextState("IDLE") ) ) diff --git a/litesata/core/link/__init__.py b/litesata/core/link/__init__.py index 64884eee..b6abd9df 100644 --- a/litesata/core/link/__init__.py +++ b/litesata/core/link/__init__.py @@ -110,6 +110,7 @@ class LiteSATALinkTX(Module): class LiteSATALinkRX(Module): def __init__(self, phy): self.source = Source(link_description(32)) + self.hold = Signal() self.to_tx = Source(from_rx) ### @@ -152,15 +153,11 @@ class LiteSATALinkRX(Module): crc_error.eq(crc.source.error) ) - # small fifo to manage HOLD - self.fifo = SyncFIFO(link_description(32), 32) - # graph self.comb += [ cont.source.ack.eq(1), Record.connect(scrambler.source, crc.sink), - Record.connect(crc.source, self.fifo.sink), - Record.connect(self.fifo.source, self.source) + Record.connect(crc.source, self.source), ] cont_source_data_d = Signal(32) self.sync += \ @@ -198,7 +195,7 @@ class LiteSATALinkRX(Module): insert.eq(primitives["HOLDA"]) ).Elif(det == primitives["EOF"], NextState("WTRM") - ).Elif(self.fifo.fifo.level > 8, + ).Elif(self.hold, insert.eq(primitives["HOLD"]) ) ) @@ -237,8 +234,15 @@ class LiteSATALinkRX(Module): ] class LiteSATALink(Module): - def __init__(self, phy): + def __init__(self, phy, buffer_depth): + self.tx_buffer = PacketBuffer(link_description(32), buffer_depth) self.tx = LiteSATALinkTX(phy) self.rx = LiteSATALinkRX(phy) - self.comb += Record.connect(self.rx.to_tx, self.tx.from_rx) - self.sink, self.source = self.tx.sink, self.rx.source + self.rx_buffer = PacketBuffer(link_description(32), buffer_depth, almost_full=3*buffer_depth//4) + self.comb += [ + Record.connect(self.tx_buffer.source, self.tx.sink), + Record.connect(self.rx.to_tx, self.tx.from_rx), + Record.connect(self.rx.source, self.rx_buffer.sink), + self.rx.hold.eq(self.rx_buffer.almost_full) + ] + self.sink, self.source = self.tx_buffer.sink, self.rx_buffer.source diff --git a/litesata/frontend/bist.py b/litesata/frontend/bist.py index 02abd3b9..afb8daef 100644 --- a/litesata/frontend/bist.py +++ b/litesata/frontend/bist.py @@ -128,7 +128,7 @@ class LiteSATABISTChecker(Module): If(sink.stb, counter.ce.eq(1), If(sink.data != expected_data, - self.error_counter.ce.eq(1) + self.error_counter.ce.eq(~sink.last) ), If(sink.eop, If(sink.last, diff --git a/litesata/test/command_tb.py b/litesata/test/command_tb.py index b5c9dc49..0b9d53a0 100644 --- a/litesata/test/command_tb.py +++ b/litesata/test/command_tb.py @@ -59,7 +59,7 @@ class TB(Module): link_debug=False, link_random_level=50, transport_debug=False, transport_loopback=False, hdd_debug=True) - self.core = LiteSATACore(self.hdd.phy) + self.core = LiteSATACore(self.hdd.phy, buffer_depth=512) self.streamer = CommandStreamer() self.streamer_randomizer = Randomizer(command_tx_description(32), level=50) diff --git a/litesata/test/link_tb.py b/litesata/test/link_tb.py index daca230d..17abe2c8 100644 --- a/litesata/test/link_tb.py +++ b/litesata/test/link_tb.py @@ -17,7 +17,7 @@ class TB(Module): self.hdd = HDD( link_debug=False, link_random_level=50, transport_debug=False, transport_loopback=True) - self.link = InsertReset(LiteSATALink(self.hdd.phy)) + self.link = InsertReset(LiteSATALink(self.hdd.phy, buffer_depth=512)) self.streamer = LinkStreamer() self.streamer_randomizer = Randomizer(link_description(32), level=50) diff --git a/targets/bist.py b/targets/bist.py index 144bf8dc..29581b28 100644 --- a/targets/bist.py +++ b/targets/bist.py @@ -202,7 +202,7 @@ class BISTSoCDevel(BISTSoC, AutoCSR): self.mila = MiLa(depth=2048, dat=Cat(*debug)) self.mila.add_port(Term) if export_mila: - mila_filename = os.path.join(platform.soc_ext_path, "test", "mila.csv") + mila_filename = os.path.join("test", "mila.csv") self.mila.export(self, debug, mila_filename) def do_finalize(self): diff --git a/test/test_link.py b/test/test_link.py index 46e41411..fa4a5d0a 100644 --- a/test/test_link.py +++ b/test/test_link.py @@ -18,27 +18,27 @@ if len(sys.argv) < 2: conditions = {} conditions["wr_cmd"] = { - "bistsocdevel_core_sink_stb" : 1, - "bistsocdevel_core_sink_payload_write" : 1, + "sata_command_tx_sink_stb" : 1, + "sata_command_tx_sink_payload_write" : 1, } conditions["wr_dma_activate"] = { - "bistsocdevel_core_source_source_stb" : 1, - "bistsocdevel_core_source_source_payload_write" : 1, + "sata_command_rx_source_stb" : 1, + "sata_command_rx_source_payload_write" : 1, } conditions["rd_cmd"] = { - "bistsocdevel_core_sink_stb" : 1, - "bistsocdevel_core_sink_payload_read" : 1, + "sata_command_tx_sink_stb" : 1, + "sata_command_tx_sink_payload_read" : 1, } conditions["rd_data"] = { - "bistsocdevel_core_source_source_stb" : 1, - "bistsocdevel_core_source_source_payload_read" : 1, + "sata_command_rx_source_stb" : 1, + "sata_command_rx_source_payload_read" : 1, } conditions["id_cmd"] = { - "bistsocdevel_core_sink_stb" : 1, - "bistsocdevel_core_sink_payload_identify" : 1, + "sata_command_tx_sink_stb" : 1, + "sata_command_tx_sink_payload_identify" : 1, } conditions["id_pio_setup"] = { - "bistsocdevel_source_source_payload_data" : primitives["X_RDY"], + "source_source_payload_data" : primitives["X_RDY"], } mila.prog_term(port=0, cond=conditions[sys.argv[1]]) @@ -47,9 +47,9 @@ mila.prog_sum("term") # Trigger / wait / receive mila.trigger(offset=512, length=2000) -identify.run() +#identify.run() generator.run(0, 2, 0) -checker.run(0, 2, 0) +#checker.run(0, 2, 0) mila.wait_done() mila.read() @@ -57,7 +57,10 @@ mila.export("dump.vcd") ### wb.close() -print_link_trace(mila, - tx_data_name="bistsocdevel_sink_sink_payload_data", - rx_data_name="bistsocdevel_source_source_payload_data" +f = open("dump_link.txt", "w") +data = link_trace(mila, + tx_data_name="sink_sink_payload_data", + rx_data_name="source_source_payload_data" ) +f.write(data) +f.close()