mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
litesata: use new Migen modules from actorlib/packet.py (avoid duplications between cores)
This commit is contained in:
parent
fe867ccf33
commit
ded3f22574
3 changed files with 82 additions and 212 deletions
|
@ -9,9 +9,11 @@ from migen.genlib.misc import chooser, optree, Counter, Timeout
|
|||
from migen.genlib.cdc import *
|
||||
from migen.flow.actor import *
|
||||
from migen.flow.plumbing import Multiplexer, Demultiplexer
|
||||
from migen.flow.plumbing import Buffer
|
||||
from migen.actorlib.fifo import *
|
||||
from migen.actorlib.structuring import Pipeline, Converter
|
||||
from migen.actorlib.packet import Buffer
|
||||
from migen.actorlib.misc import BufferizeEndpoints
|
||||
from migen.actorlib.packet import HeaderField, Header
|
||||
|
||||
bitrates = {
|
||||
"sata_gen3": 6.0,
|
||||
|
@ -84,76 +86,84 @@ fis_types = {
|
|||
"DATA": 0x46
|
||||
}
|
||||
|
||||
fis_reg_h2d_header_length = 5
|
||||
fis_reg_h2d_header_fields = {
|
||||
"type": HeaderField(0*4, 0, 8),
|
||||
"pm_port": HeaderField(0*4, 8, 4),
|
||||
"c": HeaderField(0*4, 15, 1),
|
||||
"command": HeaderField(0*4, 16, 8),
|
||||
"features_lsb": HeaderField(0*4, 24, 8),
|
||||
|
||||
class FISField():
|
||||
def __init__(self, dword, offset, width):
|
||||
self.dword = dword
|
||||
self.offset = offset
|
||||
self.width = width
|
||||
"lba_lsb": HeaderField(1*4, 0, 24),
|
||||
"device": HeaderField(1*4, 24, 8),
|
||||
|
||||
fis_reg_h2d_cmd_len = 5
|
||||
fis_reg_h2d_layout = {
|
||||
"type": FISField(0, 0, 8),
|
||||
"pm_port": FISField(0, 8, 4),
|
||||
"c": FISField(0, 15, 1),
|
||||
"command": FISField(0, 16, 8),
|
||||
"features_lsb": FISField(0, 24, 8),
|
||||
"lba_msb": HeaderField(2*4, 0, 24),
|
||||
"features_msb": HeaderField(2*4, 24, 8),
|
||||
|
||||
"lba_lsb": FISField(1, 0, 24),
|
||||
"device": FISField(1, 24, 8),
|
||||
|
||||
"lba_msb": FISField(2, 0, 24),
|
||||
"features_msb": FISField(2, 24, 8),
|
||||
|
||||
"count": FISField(3, 0, 16),
|
||||
"icc": FISField(3, 16, 8),
|
||||
"control": FISField(3, 24, 8)
|
||||
"count": HeaderField(3*4, 0, 16),
|
||||
"icc": HeaderField(3*4, 16, 8),
|
||||
"control": HeaderField(3*4, 24, 8)
|
||||
}
|
||||
fis_reg_h2d_header = Header(fis_reg_h2d_header_fields,
|
||||
fis_reg_h2d_header_length,
|
||||
swap_field_bytes=False)
|
||||
|
||||
fis_reg_d2h_cmd_len = 5
|
||||
fis_reg_d2h_layout = {
|
||||
"type": FISField(0, 0, 8),
|
||||
"pm_port": FISField(0, 8, 4),
|
||||
"i": FISField(0, 14, 1),
|
||||
"status": FISField(0, 16, 8),
|
||||
"error": FISField(0, 24, 8),
|
||||
fis_reg_d2h_header_length = 5
|
||||
fis_reg_d2h_header_fields = {
|
||||
"type": HeaderField(0*4, 0, 8),
|
||||
"pm_port": HeaderField(0*4, 8, 4),
|
||||
"i": HeaderField(0*4, 14, 1),
|
||||
"status": HeaderField(0*4, 16, 8),
|
||||
"error": HeaderField(0*4, 24, 8),
|
||||
|
||||
"lba_lsb": FISField(1, 0, 24),
|
||||
"device": FISField(1, 24, 8),
|
||||
"lba_lsb": HeaderField(1*4, 0, 24),
|
||||
"device": HeaderField(1*4, 24, 8),
|
||||
|
||||
"lba_msb": FISField(2, 0, 24),
|
||||
"lba_msb": HeaderField(2*4, 0, 24),
|
||||
|
||||
"count": FISField(3, 0, 16)
|
||||
"count": HeaderField(3*4, 0, 16)
|
||||
}
|
||||
fis_reg_d2h_header = Header(fis_reg_d2h_header_fields,
|
||||
fis_reg_d2h_header_length,
|
||||
swap_field_bytes=False)
|
||||
|
||||
fis_dma_activate_d2h_cmd_len = 1
|
||||
fis_dma_activate_d2h_layout = {
|
||||
"type": FISField(0, 0, 8),
|
||||
"pm_port": FISField(0, 8, 4)
|
||||
fis_dma_activate_d2h_header_length = 1
|
||||
fis_dma_activate_d2h_header_fields = {
|
||||
"type": HeaderField(0*4, 0, 8),
|
||||
"pm_port": HeaderField(0*4, 8, 4)
|
||||
}
|
||||
fis_dma_activate_d2h_header = Header(fis_dma_activate_d2h_header_fields,
|
||||
fis_dma_activate_d2h_header_length,
|
||||
swap_field_bytes=False)
|
||||
|
||||
fis_pio_setup_d2h_cmd_len = 5
|
||||
fis_pio_setup_d2h_layout = {
|
||||
"type": FISField(0, 0, 8),
|
||||
"pm_port": FISField(0, 8, 4),
|
||||
"d": FISField(0, 13, 1),
|
||||
"i": FISField(0, 14, 1),
|
||||
"status": FISField(0, 16, 8),
|
||||
"error": FISField(0, 24, 8),
|
||||
fis_pio_setup_d2h_header_length = 5
|
||||
fis_pio_setup_d2h_header_fields = {
|
||||
"type": HeaderField(0*4, 0, 8),
|
||||
"pm_port": HeaderField(0*4, 8, 4),
|
||||
"d": HeaderField(0*4, 13, 1),
|
||||
"i": HeaderField(0*4, 14, 1),
|
||||
"status": HeaderField(0*4, 16, 8),
|
||||
"error": HeaderField(0*4, 24, 8),
|
||||
|
||||
"lba_lsb": FISField(1, 0, 24),
|
||||
"lba_lsb": HeaderField(1*4, 0, 24),
|
||||
|
||||
"lba_msb": FISField(2, 0, 24),
|
||||
"lba_msb": HeaderField(2*4, 0, 24),
|
||||
|
||||
"count": FISField(3, 0, 16),
|
||||
"count": HeaderField(3*4, 0, 16),
|
||||
|
||||
"transfer_count": FISField(4, 0, 16),
|
||||
"transfer_count": HeaderField(4*4, 0, 16),
|
||||
}
|
||||
fis_pio_setup_d2h_header = Header(fis_pio_setup_d2h_header_fields,
|
||||
fis_pio_setup_d2h_header_length,
|
||||
swap_field_bytes=False)
|
||||
|
||||
fis_data_cmd_len = 1
|
||||
fis_data_layout = {
|
||||
"type": FISField(0, 0, 8)
|
||||
fis_data_header_length = 1
|
||||
fis_data_header_fields = {
|
||||
"type": HeaderField(0, 0, 8)
|
||||
}
|
||||
fis_data_header = Header(fis_data_header_fields,
|
||||
fis_data_header_length,
|
||||
swap_field_bytes=False)
|
||||
|
||||
|
||||
def transport_tx_description(dw):
|
||||
|
@ -263,116 +273,3 @@ def dwords2sectors(n):
|
|||
|
||||
def sectors2dwords(n):
|
||||
return n*logical_sector_size//4
|
||||
|
||||
|
||||
# Generic modules
|
||||
class BufferizeEndpoints(ModuleTransformer):
|
||||
def __init__(self, *names):
|
||||
self.names = names
|
||||
|
||||
def transform_instance(self, submodule):
|
||||
endpoints = get_endpoints(submodule)
|
||||
sinks = {}
|
||||
sources = {}
|
||||
for name, endpoint in endpoints.items():
|
||||
if not self.names or name in self.names:
|
||||
if isinstance(endpoint, Sink):
|
||||
sinks.update({name: endpoint})
|
||||
elif isinstance(endpoint, Source):
|
||||
sources.update({name: endpoint})
|
||||
|
||||
# add buffer on sinks
|
||||
for name, sink in sinks.items():
|
||||
buf = Buffer(sink.description)
|
||||
submodule.submodules += buf
|
||||
setattr(self, name, buf.d)
|
||||
submodule.comb += Record.connect(buf.q, sink)
|
||||
|
||||
# add buffer on sources
|
||||
for name, source in sources.items():
|
||||
buf = Buffer(source.description)
|
||||
submodule.submodules += buf
|
||||
submodule.comb += Record.connect(source, buf.d)
|
||||
setattr(self, name, buf.q)
|
||||
|
||||
|
||||
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)
|
||||
cmd_fifo = SyncFIFO(cmd_description(), cmd_depth)
|
||||
self.submodules += cmd_fifo
|
||||
self.comb += [
|
||||
cmd_fifo.sink.stb.eq(sink_status.done),
|
||||
cmd_fifo.sink.error.eq(sink.error)
|
||||
]
|
||||
|
||||
# data
|
||||
data_fifo = SyncFIFO(description, data_depth, buffered=True)
|
||||
self.submodules += data_fifo
|
||||
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")
|
||||
self.submodules += fsm
|
||||
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)
|
||||
|
|
|
@ -246,10 +246,10 @@ class LiteSATALinkRX(Module):
|
|||
|
||||
class LiteSATALink(Module):
|
||||
def __init__(self, phy, buffer_depth):
|
||||
self.submodules.tx_buffer = PacketBuffer(link_description(32), buffer_depth)
|
||||
self.submodules.tx_buffer = Buffer(link_description(32), buffer_depth)
|
||||
self.submodules.tx = LiteSATALinkTX(phy)
|
||||
self.submodules.rx = LiteSATALinkRX(phy)
|
||||
self.submodules.rx_buffer = PacketBuffer(link_description(32), buffer_depth,
|
||||
self.submodules.rx_buffer = Buffer(link_description(32), buffer_depth,
|
||||
almost_full=3*buffer_depth//4)
|
||||
self.comb += [
|
||||
Record.connect(self.tx_buffer.source, self.tx.sink),
|
||||
|
|
|
@ -1,26 +1,6 @@
|
|||
from misoclib.mem.litesata.common import *
|
||||
|
||||
|
||||
def _get_item(obj, name, width):
|
||||
if "_lsb" in name:
|
||||
item = getattr(obj, name.replace("_lsb", ""))[:width]
|
||||
elif "_msb" in name:
|
||||
item = getattr(obj, name.replace("_msb", ""))[width:2*width]
|
||||
else:
|
||||
item = getattr(obj, name)
|
||||
return item
|
||||
|
||||
|
||||
def _encode_cmd(obj, description, signal):
|
||||
r = []
|
||||
for k, v in sorted(description.items()):
|
||||
start = v.dword*32 + v.offset
|
||||
end = start + v.width
|
||||
item = _get_item(obj, k, v.width)
|
||||
r.append(signal[start:end].eq(item))
|
||||
return r
|
||||
|
||||
|
||||
def test_type(name, signal):
|
||||
return signal == fis_types[name]
|
||||
|
||||
|
@ -31,7 +11,8 @@ class LiteSATATransportTX(Module):
|
|||
|
||||
# # #
|
||||
|
||||
cmd_ndwords = max(fis_reg_h2d_cmd_len, fis_data_cmd_len)
|
||||
cmd_ndwords = max(fis_reg_h2d_header.length,
|
||||
fis_data_header.length)
|
||||
encoded_cmd = Signal(cmd_ndwords*32)
|
||||
|
||||
counter = Counter(max=cmd_ndwords+1)
|
||||
|
@ -72,8 +53,8 @@ class LiteSATATransportTX(Module):
|
|||
If(update_fis_type, fis_type.eq(link.source.d[:8]))
|
||||
|
||||
fsm.act("SEND_CTRL_CMD",
|
||||
_encode_cmd(sink, fis_reg_h2d_layout, encoded_cmd),
|
||||
cmd_len.eq(fis_reg_h2d_cmd_len-1),
|
||||
fis_reg_h2d_header.encode(sink, encoded_cmd),
|
||||
cmd_len.eq(fis_reg_h2d_header.length-1),
|
||||
cmd_send.eq(1),
|
||||
If(cmd_done,
|
||||
sink.ack.eq(1),
|
||||
|
@ -82,8 +63,8 @@ class LiteSATATransportTX(Module):
|
|||
)
|
||||
fsm.act("SEND_DATA_CMD",
|
||||
sink.ack.eq(0),
|
||||
_encode_cmd(sink, fis_data_layout, encoded_cmd),
|
||||
cmd_len.eq(fis_data_cmd_len-1),
|
||||
fis_data_header.encode(sink, encoded_cmd),
|
||||
cmd_len.eq(fis_data_header.length-1),
|
||||
cmd_with_data.eq(1),
|
||||
cmd_send.eq(1),
|
||||
If(cmd_done,
|
||||
|
@ -121,24 +102,16 @@ class LiteSATATransportTX(Module):
|
|||
]
|
||||
|
||||
|
||||
def _decode_cmd(signal, description, obj):
|
||||
r = []
|
||||
for k, v in sorted(description.items()):
|
||||
start = v.dword*32+v.offset
|
||||
end = start+v.width
|
||||
item = _get_item(obj, k, v.width)
|
||||
r.append(item.eq(signal[start:end]))
|
||||
return r
|
||||
|
||||
|
||||
class LiteSATATransportRX(Module):
|
||||
def __init__(self, link):
|
||||
self.source = source = Source(transport_rx_description(32))
|
||||
|
||||
# # #
|
||||
|
||||
cmd_ndwords = max(fis_reg_d2h_cmd_len, fis_dma_activate_d2h_cmd_len,
|
||||
fis_pio_setup_d2h_cmd_len, fis_data_cmd_len)
|
||||
cmd_ndwords = max(fis_reg_d2h_header.length,
|
||||
fis_dma_activate_d2h_header.length,
|
||||
fis_pio_setup_d2h_header.length,
|
||||
fis_data_header.length)
|
||||
encoded_cmd = Signal(cmd_ndwords*32)
|
||||
|
||||
counter = Counter(max=cmd_ndwords+1)
|
||||
|
@ -186,11 +159,11 @@ class LiteSATATransportRX(Module):
|
|||
|
||||
fsm.act("RECEIVE_CTRL_CMD",
|
||||
If(test_type("REG_D2H", fis_type),
|
||||
cmd_len.eq(fis_reg_d2h_cmd_len-1)
|
||||
cmd_len.eq(fis_reg_d2h_header.length-1)
|
||||
).Elif(test_type("DMA_ACTIVATE_D2H", fis_type),
|
||||
cmd_len.eq(fis_dma_activate_d2h_cmd_len-1)
|
||||
cmd_len.eq(fis_dma_activate_d2h_header.length-1)
|
||||
).Else(
|
||||
cmd_len.eq(fis_pio_setup_d2h_cmd_len-1)
|
||||
cmd_len.eq(fis_pio_setup_d2h_header.length-1)
|
||||
),
|
||||
cmd_receive.eq(1),
|
||||
link.source.ack.eq(1),
|
||||
|
@ -203,18 +176,18 @@ class LiteSATATransportRX(Module):
|
|||
source.sop.eq(1),
|
||||
source.eop.eq(1),
|
||||
If(test_type("REG_D2H", fis_type),
|
||||
_decode_cmd(encoded_cmd, fis_reg_d2h_layout, source),
|
||||
fis_reg_d2h_header.decode(encoded_cmd, source)
|
||||
).Elif(test_type("DMA_ACTIVATE_D2H", fis_type),
|
||||
_decode_cmd(encoded_cmd, fis_dma_activate_d2h_layout, source),
|
||||
fis_dma_activate_d2h_header.decode(encoded_cmd, source)
|
||||
).Else(
|
||||
_decode_cmd(encoded_cmd, fis_pio_setup_d2h_layout, source),
|
||||
fis_pio_setup_d2h_header.decode(encoded_cmd, source)
|
||||
),
|
||||
If(source.stb & source.ack,
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
fsm.act("RECEIVE_DATA_CMD",
|
||||
cmd_len.eq(fis_data_cmd_len-1),
|
||||
cmd_len.eq(fis_data_header.length-1),
|
||||
cmd_receive.eq(1),
|
||||
link.source.ack.eq(1),
|
||||
If(cmd_done,
|
||||
|
@ -224,7 +197,7 @@ class LiteSATATransportRX(Module):
|
|||
fsm.act("PRESENT_DATA",
|
||||
data_receive.eq(1),
|
||||
source.stb.eq(link.source.stb),
|
||||
_decode_cmd(encoded_cmd, fis_data_layout, source),
|
||||
fis_data_header.decode(encoded_cmd, source),
|
||||
source.sop.eq(data_sop),
|
||||
source.eop.eq(link.source.eop),
|
||||
source.error.eq(link.source.error),
|
||||
|
|
Loading…
Reference in a new issue