link: test RX path
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 5 Dec 2014 19:26:09 +0000 (20:26 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 5 Dec 2014 19:26:09 +0000 (20:26 +0100)
lib/sata/link/__init__.py
lib/sata/link/cont.py
lib/sata/link/scrambler.py
lib/sata/test/bfm.py
lib/sata/test/link_tb.py

index dff5972576c4ac8b74e97783a7c004f03af99af8..ebbc76b4bd3620a41cd9631fcbc6efd36c9f98a8 100644 (file)
@@ -6,8 +6,8 @@ from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
 from lib.sata.link.scrambler import SATAScrambler
 from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
 
-# TODO:
-# - Do more tests
+#TODO:
+# -Test HOLD on RX path
 
 from_rx = [
        ("idle", 1),
@@ -67,16 +67,19 @@ class SATALinkLayerTX(Module):
 
                # FSM
                fsm.act("IDLE",
-                       insert.eq(primitives["SYNC"]),
-                       If(scrambler.source.stb & scrambler.source.sop,
-                               If(self.from_rx.idle,
-                                       NextState("RDY")
+                       scrambler.reset.eq(1),
+                       If(self.from_rx.idle,
+                               insert.eq(primitives["SYNC"]),
+                               If(scrambler.source.stb & scrambler.source.sop,
+                                       NextState("RDY"),
                                )
                        )
                )
                fsm.act("RDY",
                        insert.eq(primitives["X_RDY"]),
-                       If(self.from_rx.det == primitives["R_RDY"],
+                       If(~self.from_rx.idle,
+                               NextState("IDLE")
+                       ).Elif(self.from_rx.det == primitives["R_RDY"],
                                NextState("SOF")
                        )
                )
@@ -141,12 +144,25 @@ class SATALinkLayerRX(Module):
                crc = SATACRCChecker(link_layout(32))
                self.submodules += crc
 
+               sop = Signal()
+               self.sync += \
+                       If(fsm.ongoing("RDY"),
+                               sop.eq(1)
+                       ).Elif(scrambler.sink.stb & scrambler.sink.ack,
+                               sop.eq(0)
+                       )
+
                # graph
-               self.comb += [
+               self.sync += \
                        If(fsm.ongoing("COPY") & (det == 0),
                                scrambler.sink.stb.eq(cont.source.stb & (cont.source.charisk == 0)),
                                scrambler.sink.d.eq(cont.source.data),
-                       ),
+                       ).Else(
+                               scrambler.sink.stb.eq(0)
+                       )
+               self.comb += [
+                       scrambler.sink.sop.eq(sop),
+                       scrambler.sink.eop.eq(det == primitives["EOF"]),
                        cont.source.ack.eq(1),
                        Record.connect(scrambler.source, crc.sink),
                        Record.connect(crc.source, self.source)
@@ -154,6 +170,7 @@ class SATALinkLayerRX(Module):
 
                # FSM
                fsm.act("IDLE",
+                       scrambler.reset.eq(1),
                        If(det == primitives["X_RDY"],
                                NextState("RDY")
                        )
@@ -165,6 +182,7 @@ class SATALinkLayerRX(Module):
                        )
                )
                fsm.act("COPY",
+                       insert.eq(primitives["R_IP"]),
                        If(det == primitives["HOLD"],
                                insert.eq(primitives["HOLDA"])
                        ).Elif(det == primitives["EOF"],
index 447e9179d35ba3ac5451377be8d6f69f02c30253..63f5f733598321fba10159846b9e33d9ec254cd3 100644 (file)
@@ -48,7 +48,7 @@ class SATACONTInserter(Module):
                        )
 
                # scrambler (between CONT and next primitive)
-               scrambler = Scrambler()
+               scrambler = InsertReset(Scrambler())
                self.submodules += scrambler
                self.comb += [
                        scrambler.reset.eq(ResetSignal()), #XXX: should be reseted on COMINIT / COMRESET
index 5f4a0faa98495f29310f2c3b019743fa4575e4bb..9d8783db638c969335662142e794aad856704f85 100644 (file)
@@ -3,7 +3,6 @@ from migen.genlib.misc import optree
 
 from lib.sata.std import *
 
-@DecorateModule(InsertReset)
 @DecorateModule(InsertCE)
 class Scrambler(Module):
        """SATA Scrambler
@@ -68,6 +67,7 @@ class Scrambler(Module):
 
                self.comb += self.value.eq(next_value)
 
+@DecorateModule(InsertReset)
 class SATAScrambler(Module):
        def __init__(self, layout):
                self.sink = sink = Sink(layout)
@@ -76,18 +76,8 @@ class SATAScrambler(Module):
                ###
 
                self.submodules.scrambler = Scrambler()
-               ongoing = Signal()
-               self.sync += \
-                       If(sink.stb & sink.ack,
-                               If(sink.eop,
-                                       ongoing.eq(0)
-                               ).Elif(sink.sop,
-                                       ongoing.eq(1)
-                               )
-                       )
                self.comb += [
-                       self.scrambler.ce.eq(sink.stb & sink.ack & (sink.sop | ongoing)),
-                       self.scrambler.reset.eq(~(sink.sop | ongoing)),
+                       self.scrambler.ce.eq(sink.stb & sink.ack),
                        Record.connect(sink, source),
                        source.d.eq(sink.d ^ self.scrambler.value)
                ]
index 5f09028822ed6eee3b67b09d2f2f3f6ae03b6798..6272dd94e482366df7923ac0d34e4b35c7694f39 100644 (file)
@@ -49,7 +49,7 @@ class PHYSink(Module):
                        self.dword.dat = selfp.sink.data
 
 class PHYLayer(Module):
-       def __init__(self, debug):
+       def __init__(self, debug=False):
                self.debug = debug
 
                self.submodules.rx = PHYSink()
@@ -116,8 +116,8 @@ class LinkRXPacket(LinkPacket):
 
 class LinkTXPacket(LinkPacket):
        def encode(self):
-               self.scramble()
                self.insert_crc()
+               self.scramble()
 
        def scramble(self):
                for i in range(len(self)):
@@ -125,7 +125,7 @@ class LinkTXPacket(LinkPacket):
 
        def insert_crc(self):
                stdin = ""
-               for v in self[:-1]:
+               for v in self:
                        stdin += "0x%08x " %v
                stdin += "exit"
                with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
@@ -135,16 +135,20 @@ class LinkTXPacket(LinkPacket):
                self.append(crc)
 
 class LinkLayer(Module):
-       def  __init__(self, phy, debug, hold_random_level=0):
+       def  __init__(self, phy, debug=False, random_level=0):
                self.phy = phy
                self.debug = debug
-               self.hold_random_level = hold_random_level
+               self.random_level = random_level
+               self.tx_packets = []
                self.tx_packet = LinkTXPacket()
                self.rx_packet = LinkRXPacket()
                self.rx_cont = False
 
                self.transport_callback = None
 
+               self.send_state = ""
+               self.send_states = ["RDY", "SOF", "DATA", "EOF", "WTRM"]
+
        def set_transport_callback(self, callback):
                self.transport_callback = callback
 
@@ -156,42 +160,68 @@ class LinkLayer(Module):
 
                if dword == primitives["X_RDY"]:
                        self.phy.send(primitives["R_RDY"])
-
                elif dword == primitives["WTRM"]:
                        self.phy.send(primitives["R_OK"])
-
+                       if self.rx_packet.ongoing:
+                               self.rx_packet.decode()
+                               if self.transport_callback is not None:
+                                       self.transport_callback(self.rx_packet)
+                               self.rx_packet.ongoing = False
                elif dword == primitives["HOLD"]:
                        self.phy.send(primitives["HOLDA"])
-
                elif dword == primitives["EOF"]:
-                       self.rx_packet.decode()
-                       if self.transport_callback is not None:
-                               self.transport_callback(self.rx_packet)
-                       self.rx_packet.ongoing = False
-
+                       pass
                elif self.rx_packet.ongoing:
                        if dword != primitives["HOLD"]:
                                n = randn(100)
-                               if n < self.hold_random_level:
+                               if n < self.random_level:
                                        self.phy.send(primitives["HOLD"])
                                else:
-                                       self.phy.send(primitives["R_RDY"])
+                                       self.phy.send(primitives["R_IP"])
                                if not is_primitive(dword):
                                        if not self.rx_cont:
                                                self.rx_packet.append(dword)
-
                elif dword == primitives["SOF"]:
                        self.rx_packet = LinkRXPacket()
                        self.rx_packet.ongoing = True
 
-       def send(self, packet):
-               pass
+       def send(self, dword):
+               if self.send_state == "RDY":
+                       self.phy.send(primitives["X_RDY"])
+                       if dword == primitives["R_RDY"]:
+                               self.send_state = "SOF"
+               elif self.send_state == "SOF":
+                       self.phy.send(primitives["SOF"])
+                       self.send_state = "DATA"
+               elif self.send_state == "DATA":
+                       self.phy.send(self.tx_packet.pop(0))
+                       if len(self.tx_packet) == 0:
+                               self.send_state = "EOF"
+               elif self.send_state == "EOF":
+                       self.phy.send(primitives["EOF"])
+                       self.send_state = "WTRM"
+               elif self.send_state == "WTRM":
+                       self.phy.send(primitives["WTRM"])
+                       if dword == primitives["R_OK"]:
+                               self.tx_packet.done = True
+                       elif dword == primitives["R_ERR"]:
+                               self.tx_packet.done = True
 
        def gen_simulation(self, selfp):
-               self.phy.send(primitives["SYNC"])
+               self.tx_packet.done = True
                while True:
                        yield from self.phy.receive()
-                       self.callback(self.phy.rx.dword.dat)
+                       self.phy.send(primitives["SYNC"])
+                       rx_dword = self.phy.rx.dword.dat
+                       if len(self.tx_packets) != 0:
+                               if self.tx_packet.done:
+                                       self.tx_packet = self.tx_packets.pop(0)
+                                       self.tx_packet.encode()
+                                       self.send_state = "RDY"
+                       if not self.tx_packet.done:
+                               self.send(rx_dword)
+                       else:
+                               self.callback(self.phy.rx.dword.dat)
 
 def get_field_data(field, packet):
        return (packet[field.dword] >> field.offset) & (2**field.width-1)
@@ -282,8 +312,11 @@ class FIS_UNKNOWN(FIS):
                return r
 
 class TransportLayer(Module):
-       def __init__(self, link):
-               pass
+       def __init__(self, link, debug=False, loopback=False):
+               self.link = link
+               self.debug = debug
+               self.loopback = loopback
+               self.link.set_transport_callback(self.callback)
 
        def callback(self, packet):
                fis_type = packet[0]
@@ -301,12 +334,19 @@ class TransportLayer(Module):
                        fis = FIS_PIO_SETUP_D2H(packet)
                else:
                        fis = FIS_UNKNOWN(packet)
-               print(fis)
+               if self.debug:
+                       print(fis)
+               if self.loopback:
+                       packet = LinkTXPacket(fis.packet)
+                       self.link.tx_packets.append(packet)
 
 class BFM(Module):
-       def __init__(self, dw, debug=False, hold_random_level=0):
+       def __init__(self,
+                       phy_debug=False,
+                       link_debug=False, link_random_level=0,
+                       transport_debug=False, transport_loopback=False
+                       ):
                ###
-               self.submodules.phy = PHYLayer(debug)
-               self.submodules.link = LinkLayer(self.phy, debug, hold_random_level)
-               self.submodules.transport = TransportLayer(self.link)
-               self.link.set_transport_callback(self.transport.callback)
+               self.submodules.phy = PHYLayer(phy_debug)
+               self.submodules.link = LinkLayer(self.phy, link_debug, link_random_level)
+               self.submodules.transport = TransportLayer(self.link, transport_debug, transport_loopback)
index f2d63ce68f74ad423fefc3b2b3630ab01e5ce438..a8ea97b2fd8c22262e07bc61f04e05fc6fc4e8ef 100644 (file)
@@ -11,8 +11,8 @@ from lib.sata.test.bfm import *
 from lib.sata.test.common import *
 
 class LinkStreamer(Module):
-       def __init__(self, dw):
-               self.source = Source(link_layout(dw))
+       def __init__(self):
+               self.source = Source(link_layout(32))
                ###
                self.packets = []
                self.packet = LinkTXPacket()
@@ -43,8 +43,8 @@ class LinkStreamer(Module):
                                selfp.source.stb = 0
 
 class LinkLogger(Module):
-       def __init__(self, dw):
-               self.sink = Sink(link_layout(dw))
+       def __init__(self):
+               self.sink = Sink(link_layout(32))
                ###
                self.packet = LinkRXPacket()
 
@@ -57,6 +57,7 @@ class LinkLogger(Module):
                selfp.sink.ack = 1
                if selfp.sink.stb == 1 and selfp.sink.sop == 1:
                        self.packet = LinkRXPacket()
+                       print("rx : %08x" %selfp.sink.d)
                        self.packet.append(selfp.sink.d)
                elif selfp.sink.stb:
                        self.packet.append(selfp.sink.d)
@@ -65,13 +66,14 @@ class LinkLogger(Module):
 
 class TB(Module):
        def __init__(self):
-               self.submodules.bfm = BFM(32, debug=True, hold_random_level=50)
+               self.submodules.bfm = BFM(phy_debug=False,
+                               link_random_level=50, transport_debug=False, transport_loopback=True)
                self.submodules.link_layer = SATALinkLayer(self.bfm.phy)
 
-               self.submodules.streamer = LinkStreamer(32)
+               self.submodules.streamer = LinkStreamer()
                streamer_ack_randomizer = AckRandomizer(link_layout(32), level=50)
                self.submodules += streamer_ack_randomizer
-               self.submodules.logger = LinkLogger(32)
+               self.submodules.logger = LinkLogger()
                self.comb += [
                        Record.connect(self.streamer.source, streamer_ack_randomizer.sink),
                        Record.connect(streamer_ack_randomizer.source, self.link_layer.sink),
@@ -79,10 +81,16 @@ class TB(Module):
                ]
 
        def gen_simulation(self, selfp):
-               for i in range(200):
+               for i in range(24):
                        yield
                for i in range(8):
                        yield from self.streamer.send(LinkTXPacket([i for i in range(16)]))
+                       yield from self.logger.receive()
+                       print("Logger:")
+                       print("-------")
+                       for v in self.logger.packet:
+                               print("%08x" %v)
+
 
 if __name__ == "__main__":
        run_simulation(TB(), ncycles=512, vcd_name="my.vcd", keep_files=True)