link: prepare simulation
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 11 Nov 2014 17:47:34 +0000 (18:47 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 11 Nov 2014 17:47:34 +0000 (18:47 +0100)
lib/sata/link/__init__.py
lib/sata/link/crc.py
lib/sata/link/scrambler.py
lib/sata/link/test/Makefile
lib/sata/link/test/bfm.py [new file with mode: 0644]
lib/sata/link/test/link_tb.py [new file with mode: 0644]
lib/sata/std.py

index 65eb8cabb8d9b7b9bc5310b8b52216dd15871f2d..4d07270931132d6843bd6dd8460777b2f9db904a 100644 (file)
@@ -1,34 +1,35 @@
 from migen.fhdl.std import *
+from migen.genlib.fsm import FSM, NextState
 
 from lib.sata.std import *
-from lib.sata.link import crc
-from lib.sata.link import scrambler
+from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
+from lib.sata.link.scrambler import SATAScrambler
 
 # Todo:
 # - TX: (optional) insert COND and scramble between COND and primitives
 # - RX: manage COND, HOLD from device
 
 class SATALinkLayer(Module):
-       def __init__(self, phy, dw=32):
-               self.sink = Sink(link_layout(dw))
-               self.source = Source(link_layout(dw))
+       def __init__(self, phy):
+               self.sink = Sink(link_layout(32))
+               self.source = Source(link_layout(32))
 
                fsm = FSM(reset_state="IDLE")
                self.submodules += fsm
 
        # TX
                # insert CRC
-               crc_inserter = crc.SATACRCInserter(link_layout(dw))
+               crc_inserter = SATACRCInserter(link_layout(32))
                self.submodules += crc_inserter
 
                # scramble
-               scrambler = scrambler.SATAScrambler(link_layout(dw))
+               scrambler = SATAScrambler(link_layout(32))
                self.submodules += scrambler
 
                # graph
                self.comb += [
                        Record.connect(self.sink, crc_inserter.sink),
-                       Record.connect(crc_inserter, scrambler)
+                       Record.connect(crc_inserter.source, scrambler.sink)
                ]
 
                # datas / primitives mux
@@ -38,9 +39,9 @@ class SATALinkLayer(Module):
                                phy.sink.stb.eq(1),
                                phy.sink.data.eq(tx_insert),
                                phy.sink.charisk.eq(0x0001),
-                       ).Elsif(fsm.ongoing("H2D_COPY"),
+                       ).Elif(fsm.ongoing("H2D_COPY"),
                                phy.sink.stb.eq(scrambler.source.stb),
-                               phy.sink.data.eq(scrambler.source.data),
+                               phy.sink.data.eq(scrambler.source.d),
                                scrambler.source.ack.eq(phy.source.ack),
                                phy.sink.charisk.eq(0)
                        )
@@ -55,19 +56,20 @@ class SATALinkLayer(Module):
                        )
 
                # descrambler
-               descrambler = descrambler.SATAScrambler(link_layout(dw))
+               descrambler = SATAScrambler(link_layout(32))
                self.submodules += descrambler
 
                # check CRC
-               crc_checker = crc.SATACRCChecker(link_layout(dw))
+               crc_checker = SATACRCChecker(link_layout(32))
                self.submodules += crc_checker
 
                # graph
                self.comb += [
                        If(fsm.ongoing("H2D_COPY") & (rx_det == 0),
-                               descrambler.sink.stb.eq(phy.source.stb & (phy.charisk == 0)),
-                               descrambler.sink.d.eq(phy.source.d),
+                               descrambler.sink.stb.eq(phy.source.stb & (phy.source.charisk == 0)),
+                               descrambler.sink.d.eq(phy.source.data),
                        ),
+                       phy.source.ack.eq(1),
                        Record.connect(descrambler.source, crc_checker.sink),
                        Record.connect(crc_checker.source, self.source)
                ]
@@ -75,9 +77,9 @@ class SATALinkLayer(Module):
        # FSM
                fsm.act("IDLE",
                        tx_insert.eq(primitives["SYNC"]),
-                       If(rx_primitive == "X_RDY",
+                       If(rx_det == primitives["X_RDY"],
                                NextState("D2H_RDY")
-                       ).Elif(scrambler.stb & scrambler.sop,
+                       ).Elif(scrambler.source.stb & scrambler.source.sop,
                                NextState("H2D_RDY")
                        )
                )
@@ -85,8 +87,9 @@ class SATALinkLayer(Module):
                # Host to Device
                fsm.act("H2D_RDY",
                        tx_insert.eq(primitives["X_RDY"]),
-                       If(rx_primitive == primitives["R_RDY"]),
+                       If(rx_det == primitives["R_RDY"],
                                NextState("H2D_SOF")
+                       )
                )
                fsm.act("H2D_SOF",
                        tx_insert.eq(primitives["SOF"]),
@@ -95,7 +98,7 @@ class SATALinkLayer(Module):
                        )
                )
                fsm.act("H2D_COPY",
-                       If(scrambler.stb & scrambler.ack & scramvbler.eop,
+                       If(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
                                NextState("H2D_EOF")
                        )
                )
index e7bb3bb0e6bb1efb1ea9c13bdb143cc19f54c8ca..2f3aa367a74a95dff0b9dee7561f9b84011398ad 100644 (file)
@@ -90,7 +90,7 @@ class SATACRC(Module):
        polynom = 0x04C11DB7
        init = 0x52325032
        check = 0xC704DD7B
-       def __init__(self):
+       def __init__(self, dat_width):
                self.d = Signal(self.width)
                self.value = Signal(self.width)
                self.error = Signal()
index 8f301a1929aaef55cf7d220a1305dd20d3ad0800..df599fec066fee32094398e123373ba1e110069f 100644 (file)
@@ -1,6 +1,8 @@
 from migen.fhdl.std import *
 from migen.genlib.misc import optree
 
+from lib.sata.std import *
+
 @DecorateModule(InsertReset)
 @DecorateModule(InsertCE)
 class Scrambler(Module):
@@ -79,7 +81,7 @@ class SATAScrambler(Module):
                        If(sink.stb & sink.ack,
                                If(sink.eop,
                                        ongoing.eq(0)
-                               ).Elsif(sink.sop,
+                               ).Elif(sink.sop,
                                        ongoing.eq(1)
                                )
                        )
index bd6ef493f03fd6bae6d2f6973310ceacc5d2ff44..4f621c37b173925fabfe7f753d1f6629cfd2b218 100644 (file)
@@ -14,6 +14,9 @@ scrambler_tb:
        $(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
        $(CMD) scrambler_tb.py
 
+link_tb:
+       $(CMD) link_tb.py
+
 all: crc_tb scrambler_tb
 
 clean:
diff --git a/lib/sata/link/test/bfm.py b/lib/sata/link/test/bfm.py
new file mode 100644 (file)
index 0000000..10c87e4
--- /dev/null
@@ -0,0 +1,88 @@
+from migen.fhdl.std import *
+
+from lib.sata.std import *
+
+class BFMDword():
+       def __init__(self, dat=0):
+               self.dat = dat
+               self.start = 1
+               self.done = 0
+
+class BFMSource(Module):
+       def __init__(self, dw):
+               self.source = Source(phy_layout(dw))
+               ###
+               self.dwords = []
+               self.dword = BFMDword()
+               self.dword.done = 1
+
+       def send(self, dword, blocking=True):
+               self.dwords.append(dword)
+               if blocking:
+                       while dword.done == 0:
+                               yield
+
+       def do_simulation(self, selfp):
+               if len(self.dwords) and self.dword.done:
+                       self.dword = self.dwords.pop(0)
+               if not self.dword.done:
+                       selfp.source.stb = 1
+                       selfp.source.charisk = 0b0000
+                       for k, v in primitives.items():
+                               if v == self.dword.dat:
+                                       selfp.source.charisk = 0b0001
+                       selfp.source.data = self.dword.dat
+               elif selfp.source.stb == 1 and selfp.source.ack == 1:
+                               self.dword.done = 1
+                               selfp.source.stb = 0
+
+class BFMSink(Module):
+       def __init__(self, dw):
+               self.sink = Sink(phy_layout(dw))
+               ###
+               self.dword = BFMDword()
+
+       def receive(self):
+               self.dword.done = 0
+               while self.dword.done == 0:
+                       yield
+
+       def do_simulation(self, selfp):
+               self.dword.done = 0
+               selfp.sink.ack = 1
+               if selfp.sink.stb == 1:
+                       self.dword.done = 1
+                       self.dword.dat = selfp.sink.data
+
+class BFMPHY(Module):
+       def __init__(self, dw):
+               self.dw = dw
+
+               self.submodules.bfm_sink = BFMSink(dw)
+               self.submodules.bfm_source = BFMSource(dw)
+
+               self.source = self.bfm_source.source
+               self.sink = self.bfm_sink.sink
+
+               self.dword = 0
+
+       def send(self, dword, blocking=True):
+               packet = BFMDword(dword)
+               yield from self.bfm_source.send(dword, blocking)
+
+       def receive(self):
+               yield from self.bfm_sink.receive()
+               self.rx_dword = self.bfm_sink.dword.dat
+
+class BFM(Module):
+       def __init__(self, dw, debug=False):
+               self.debug = debug
+
+               ###
+
+               self.submodules.phy = BFMPHY(dw)
+
+       def gen_simulation(self, selfp):
+               while True:
+                       yield from self.phy.receive()
+                       print("%08x" %(self.phy.rx_dword))
diff --git a/lib/sata/link/test/link_tb.py b/lib/sata/link/test/link_tb.py
new file mode 100644 (file)
index 0000000..7753e5b
--- /dev/null
@@ -0,0 +1,90 @@
+from migen.fhdl.std import *
+from migen.genlib.record import *
+from migen.sim.generic import run_simulation
+
+from lib.sata.std import *
+from lib.sata.link import SATALinkLayer
+
+from lib.sata.link.test.bfm import *
+
+class LinkPacket():
+       def __init__(self, d=[]):
+               self.d = d
+               self.start = 1
+               self.done = 0
+
+class LinkStreamer(Module):
+       def __init__(self, dw):
+               self.source = Source(link_layout(dw))
+               ###
+               self.packets = []
+               self.packet = LinkPacket()
+               self.packet.done = 1
+
+       def send(self, packet, blocking=True):
+               self.packets.append(packet)
+               if blocking:
+                       while packet.done == 0:
+                               yield
+
+       def do_simulation(self, selfp):
+               if len(self.packets) and self.packet.done:
+                       self.packet = self.packets.pop(0)
+               if self.packet.start and not self.packet.done:
+                       selfp.source.stb = 1
+                       selfp.source.sop = 1
+                       selfp.source.d = self.packet.d.pop(0)
+                       self.packet.start = 0
+               elif selfp.source.stb == 1 and selfp.source.ack == 1:
+                       selfp.source.sop = 0
+                       selfp.source.eop = (len(self.packet.d) == 1)
+                       if len(self.packet.d) > 0:
+                               selfp.source.stb = 1
+                               selfp.source.d = self.packet.d.pop(0)
+                       else:
+                               self.packet.done = 1
+                               selfp.source.stb = 0
+
+class LinkLogger(Module):
+       def __init__(self, dw):
+               self.sink = Sink(link_layout(dw))
+               ###
+               self.packet = LinkPacket()
+
+       def receive(self):
+               self.packet.done = 0
+               while self.packet.done == 0:
+                       yield
+
+       def do_simulation(self, selfp):
+               self.packet.done = 0
+               selfp.sink.ack = 1
+               if selfp.sink.stb == 1 and selfp.sink.sop == 1:
+                       self.packet.start = 1
+                       self.packet.d = [selfp.sink.d]
+               elif selfp.sink.stb:
+                       self.packet.start = 0
+                       self.packet.d.append(selfp.sink.d)
+               if (selfp.sink.stb ==1 and selfp.sink.eop ==1):
+                       self.packet.done = 1
+
+class TB(Module):
+       def __init__(self):
+               self.submodules.bfm = BFM(32, debug=True)
+               self.submodules.link_layer = SATALinkLayer(self.bfm.phy)
+
+               self.submodules.streamer = LinkStreamer(32)
+               self.submodules.logger = LinkLogger(32)
+               self.comb += [
+                       self.link_layer.sink.eq(self.streamer.source),
+                       self.logger.sink.eq(self.link_layer.source)
+               ]
+
+       def gen_simulation(self, selfp):
+               for i in range(200):
+                       yield
+               yield from self.bfm.phy.send(BFMDword(primitives["R_RDY"]), False)
+               yield from self.streamer.send(LinkPacket([0, 1, 2, 3]))
+
+if __name__ == "__main__":
+       run_simulation(TB(), ncycles=5000, vcd_name="my.vcd", keep_files=True)
index a6d4c028246e1753af23c1be74d38fb696b03cde..191778fc111c373dc839cb135c03e82a41c3b44c 100644 (file)
@@ -1,6 +1,6 @@
 from migen.fhdl.std import *
 from migen.genlib.record import *
-from migen.flow.actor import EndpointDescription
+from migen.flow.actor import EndpointDescription, Sink, Source
 
 primitives = {
        "ALIGN" :       0x7B4A4ABC,
@@ -21,7 +21,7 @@ primitives = {
 def ones(width):
        return 2**width-1
 
-def phy_description(dw):
+def phy_layout(dw):
        parameters = {
                "packetized": False
        }
@@ -31,7 +31,7 @@ def phy_description(dw):
        ]
        return EndpointDescription(layout, parameters)
 
-def link_description(dw):
+def link_layout(dw):
        parameters = {
                "packetized": True
        }