add PacketBuffer, simplify architecture and reduce ressource usage
This commit is contained in:
parent
ebf1faed5b
commit
ff0c8e3d22
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
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")
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue