transport: code SATATransportLayerTX (untested)
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 11 Dec 2014 19:19:14 +0000 (20:19 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 11 Dec 2014 19:19:14 +0000 (20:19 +0100)
lib/sata/std.py
lib/sata/transport/__init__.py
lib/sata/transport/std.py

index aac6a3411f47eb78497719c54decc2af0c2ea044..bd054da3fd1673c4a5080f5651905ca4549c4a74 100644 (file)
@@ -48,13 +48,48 @@ def link_layout(dw):
        ]
        return EndpointDescription(layout, packetized=True)
 
-def transport_tx_layout(dw):
+def transport_cmd_tx_layout():
        layout = [
-               ("d", dw)
+               ("type", 8),
+               ("pm_port", 4),
+               ("a", 1),
+               ("c", 1),
+               ("d", 1),
+               ("i", 1),
+               ("command", 8),
+               ("features", 16),
+               ("lba", 48),
+               ("device", 8),
+               ("count", 16),
+               ("icc", 8),
+               ("control", 8),
+               ("dma_buffer_id", 64),
+               ("dma_buffer_offset", 32),
+               ("dma_transfer_count", 32),
+       ]
+       return EndpointDescription(layout, packetized=True)
+
+def transport_cmd_rx_layout():
+       layout = [
+               ("type", 8),
+               ("pm_port", 4),
+               ("a", 1),
+               ("d", 1),
+               ("i", 1),
+               ("status", 8),
+               ("error", 8),
+               ("lba", 48),
+               ("device", 8),
+               ("count", 16),
+               ("e_status", 8),
+               ("transfer_count", 16),
+               ("dma_buffer_id", 64),
+               ("dma_buffer_offset", 32),
+               ("dma_transfer_count", 32)
        ]
        return EndpointDescription(layout, packetized=True)
 
-def transport_rx_layout(dw):
+def transport_data_layout(dw):
        layout = [
                ("d", dw)
        ]
index a9e0042e640f81029ae9c46467454e6fbe6fcd27..ba0161dce76833ebdc819407f195a8ba00af1251 100644 (file)
 from lib.sata.std import *
 from lib.sata.transport.std import *
 
+def _encode_cmd(obj, layout, signal):
+       r = []
+       for k, v in sorted(layout.items()):
+               start = v.word*32 + v.offset
+               end = start + v.width
+               r.append(signal[start:end].eq(getattr(obj, k)))
+       return r
+
 class SATATransportLayerTX(Module):
-       def __init__(self):
-               self.sink = Sink(transport_layout(32))
+       def __init__(self, link):
+               self.cmd = cmd = Sink(transport_cmd_tx_layout())
+               self.data = data = Sink(transport_data_layout(32))
+
+               ###
+
+               cmd_ndwords = max(fis_reg_h2d_cmd_len, fis_dma_setup_cmd_len, fis_data_cmd_len)
+               encoded_cmd = Signal(cmd_ndwords*32)
+
+               cnt = Signal(max=cmd_ndwords+1)
+               clr_cnt = Signal()
+               inc_cnt = Signal()
+
+               cmd_len = Signal(flen(cnt))
+               cmd_with_data = Signal()
+
+               cmd_send = Signal()
+               data_send = Signal()
+               cmd_done = Signal()
+               data_done = Signal()
+
+               fsm = FSM(reset_state="IDLE")
+               self.submodules += fsm
+
+               # FSM
+               fsm.act("IDLE",
+                       clr_cnt.eq(1),
+                       If(cmd.stb,
+                               If(cmd.type == fis_types["REG_H2D"],
+                                       NextState("SEND_REG_H2D_CMD")
+                               ).Elif(cmd.type == "DMA_SETUP_CMD",
+                                       NextState("SEND_DMA_SETUP")
+                               ).Elif(cmd.type == "DATA_CMD"),
+                                       NextState("SEND_DATA")
+                               ).Else(
+                                       # XXX: Generate error to command layer?
+                                       cmd.ack.eq(1)
+                               )
+                       )
+               )
+               fsm.act("SEND_REG_H2D_CMD",
+                       _encode_cmd(self.cmd, fis_reg_h2d_layout, encoded_cmd),
+                       cmd_len.eq(fis_reg_h2d_cmd_len),
+                       cmd_send.eq(1)
+                       If(ack_cmd,
+                               NextState.eq("ACK")
+                       )
+               )
+               fsm.act("SEND_DMA_SETUP_CMD",
+                       _encode_cmd(self.cmd, fis_dma_setup_layout, encoded_cmd),
+                       cmd_len.eq(fis_dma_setup_cmd_len),
+                       cmd_send.eq(1),
+                       If(ack_cmd,
+                               NextState.eq("ACK")
+                       )
+               )
+               fsm.act("SEND_DATA_CMD",
+                       _encode_cmd(self.cmd, fis_data_layout, encoded_cmd),
+                       cmd_len.eq(fis_send_data_cmd_len),
+                       cmd_width_data.eq(1),
+                       cmd_send.eq(1),
+                       If(cmd_done,
+                               NextState.eq("SEND_DATA")
+                       )
+               )
+               fsm.act("SEND_DATA",
+                       data_send.eq(1),
+                       If(data_done,
+                               NextState.eq("ACK")
+                       )
+               )
+               fsm.act("ACK",
+                       cmd.ack.eq(1),
+                       NextState.eq("IDLE")
+               )
+
+               cmd_cases = {}
+               for i in range(cmd_ndwords):
+                       cmd_cases[i] = [link.sink.d.eq(encoded_cmd[32*i:32*(i+1)])]
+
+               self.comb += \
+                       If(cmd_send,
+                               link.sink.stb.eq(1),
+                               link.sink.sop.eq(cnt==0),
+                               link.sink.eop.eq((cnt==cmd_len) & ~cmd_with_data),
+                               Case(cnt, cmd_cases),
+                               inc_cnt.eq(link.sink.ack),
+                               cmd_done.eq(cnt==cmd_len)
+                       ).Elif(data_send,
+                               link.sink.stb.eq(data.stb),
+                               link.sink.sop.eq(0),
+                               link.sink.eop.eq(data.eop),
+                               link.sink.d.eq(data.d),
+                               data.ack.eq(link.sink.ack),
+                               data_done.eq(data.eop & data.ack)
+                       )
+
+               self.sync += \
+                       If(clr_cnt,
+                               cnt.eq(0)
+                       ).Elif(inc_cnt,
+                               cnt.eq(cnt+1)
+                       )
 
 class SATATransportLayerRX(Module):
-       def __init__(self):
-               self.sink = Sink(transport_layout(32))
+       def __init__(self, link):
+               self.cmd = Source(transport_cmd_rx_layout())
+               self.data = Source(transport_data_layout(32))
 
 class SATATransportLayer(Module):
-       def __init__(self):
-               self.submodules.tx = SATATransportLayerTX()
-               self.submodules.rx = SATATransportLayerRX()
+       def __init__(self, link):
+               self.submodules.tx = SATATransportLayerTX(link)
+               self.submodules.rx = SATATransportLayerRX(link)
index 03b56b2d0883bac697e92ee72ee1d04875315e8e..a38b45ee000b9207350b5fca27b689e7348a8346 100644 (file)
@@ -13,7 +13,7 @@ class FISField():
                self.offset = offset
                self.width = width
 
-fis_reg_h2d_len = 5
+fis_reg_h2d_cmd_len = 5
 fis_reg_h2d_layout = {
        "type":         FISField(0,  0, 8),
        "pm_port":      FISField(0,  8, 4),
@@ -22,7 +22,7 @@ fis_reg_h2d_layout = {
        "features_lsb": FISField(0, 24, 8),
 
        "lba_lsb":      FISField(1, 0, 24),
-       "device":       FISField(1, 24, 0),
+       "device":       FISField(1, 24, 8),
 
        "lba_msb":      FISField(2, 0, 24),
        "features_msb": FISField(2, 24, 8),
@@ -32,7 +32,7 @@ fis_reg_h2d_layout = {
        "control":      FISField(3, 24, 8)
 }
 
-fis_reg_d2h_len = 5
+fis_reg_d2h_cmd_len = 5
 fis_reg_d2h_layout = {
        "type":    FISField(0,  0, 8),
        "pm_port": FISField(0,  8, 4),
@@ -41,20 +41,20 @@ fis_reg_d2h_layout = {
        "error":   FISField(0, 24, 8),
 
        "lba_lsb": FISField(1, 0, 24),
-       "device":  FISField(1, 24, 0),
+       "device":  FISField(1, 24, 8),
 
        "lba_msb": FISField(2, 0, 24),
 
        "count":   FISField(3, 0, 16)
 }
 
-fis_dma_activate_d2h_len = 1
+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_setup_len = 7
+fis_dma_setup_cmd_len = 7
 fis_dma_setup_layout = {
        "type":               FISField(0,  0, 8),
        "pm_port":            FISField(0,  8, 4),
@@ -71,6 +71,7 @@ fis_dma_setup_layout = {
        "dma_transfer_count": FISField(4, 0, 32)
 }
 
+fis_data_cmd_len = 1
 fis_data_layout = {
        "type": FISField(0,  0, 8)
 }
@@ -85,7 +86,7 @@ fis_pio_setup_d2h_layout = {
        "error":          FISField(0, 24, 8),
 
        "lba_lsb":        FISField(1, 0, 24),
-       "device":         FISField(1, 24, 0),
+       "device":         FISField(1, 24, 8),
 
        "lba_msb":        FISField(2, 0, 24),