add phy_datapath_tb and start datapath simplification
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 19 Dec 2014 15:48:22 +0000 (16:48 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 19 Dec 2014 15:48:22 +0000 (16:48 +0100)
lib/sata/phy/datapath.py
lib/sata/test/Makefile
lib/sata/test/phy_datapath_tb.py [new file with mode: 0644]

index 6da4693f9fa53ef4b7d5cf7e245964d1cad4f459..2008ab63d48df1576428bf5d43306c4aac19f686 100644 (file)
@@ -1,6 +1,7 @@
 from lib.sata.common import *
 
 from migen.genlib.misc import chooser
+from migen.flow.plumbing import Multiplexer, Demultiplexer
 
 class SATAPHYDatapathRX(Module):
        def __init__(self):
@@ -105,6 +106,52 @@ class SATAPHYDatapathTX(Module):
                        chooser(fifo.source.charisk, mux, self.source.charisk)
                ]
 
+class SATAPHYAlignInserter(Module):
+       def __init__(self, ctrl):
+               self.sink = sink = Sink(phy_description(32))
+               self.source = source = Source(phy_description(32))
+               ###
+               # send 2 ALIGN every 256 DWORDs
+               # used for clock compensation between
+               # HOST and device
+               cnt = Signal(8)
+               send = Signal()
+               self.sync += \
+                       If(~ctrl.ready,
+                               cnt.eq(0)
+                       ).Elif(source.stb & source.ack,
+                               cnt.eq(cnt+1)
+                       )
+               self.comb += [
+                       send.eq(cnt < 2),
+                       If(send,
+                               source.stb.eq(1),
+                               source.charisk.eq(0b0001),
+                               source.data.eq(primitives["ALIGN"]),
+                               sink.ack.eq(0)
+                       ).Else(
+                               source.stb.eq(sink.stb),
+                               source.data.eq(sink.data),
+                               source.charisk.eq(sink.charisk),
+                               sink.ack.eq(source.ack)
+                       )
+               ]
+
+class SATAPHYAlignRemover(Module):
+       def __init__(self):
+               self.sink = sink = Sink(phy_description(32))
+               self.source = source = Source(phy_description(32))
+               ###
+               charisk_match = sink.charisk == 0b0001
+               data_match = sink.data == primitives["ALIGN"]
+
+               self.comb += \
+                       If(sink.stb & charisk_match & data_match,
+                               sink.ack.eq(1),
+                       ).Else(
+                               Record.connect(sink, source)
+                       )
+
 class SATAPHYDatapath(Module):
        def __init__(self, trx, ctrl):
                self.sink = Sink(phy_description(32))
@@ -112,61 +159,28 @@ class SATAPHYDatapath(Module):
 
                ###
 
-       # change data width & cross domain crossing
-               rx = SATAPHYDatapathRX()
-               tx = SATAPHYDatapathTX()
-               self.submodules += rx, tx
+       # TX path
+               self.align_inserter = SATAPHYAlignInserter(ctrl)
+               self.mux = Multiplexer(phy_description(32), 2)
+               self.tx = SATAPHYDatapathTX()
                self.comb += [
-                       trx.source.connect(rx.sink),
-                       tx.source.connect(trx.sink)
+                       self.mux.sel.eq(ctrl.ready),
+                       Record.connect(self.sink, self.align_inserter.sink),
+                       Record.connect(ctrl.source, self.mux.sink0),
+                       Record.connect(self.align_inserter.source, self.mux.sink1),
+                       Record.connect(self.mux.source, self.tx.sink),
+                       Record.connect(self.tx.source, trx.sink)
                ]
 
-       # Align cnt (send 2 Align DWORDs every 256 DWORDs)
-               align_cnt = Signal(8)
-               self.sync += \
-                       If(~ctrl.ready,
-                               align_cnt.eq(0)
-                       ).Elif(tx.sink.stb & tx.sink.ack,
-                               align_cnt.eq(align_cnt+1)
-                       )
-               send_align = (align_cnt < 2)
-
-               receive_align = Signal()
-               self.comb += receive_align.eq(rx.source.stb &
-                                               (rx.source.charisk == 0b0001) &
-                                               (rx.source.data == primitives["ALIGN"]))
-
-       # user / ctrl mux
+       # RX path
+               self.rx = SATAPHYDatapathRX()
+               self.demux = Demultiplexer(phy_description(32), 2)
+               self.align_remover = SATAPHYAlignRemover()
                self.comb += [
-                       # user
-                       If(ctrl.ready,
-                               If(send_align,
-                                       tx.sink.stb.eq(1),
-                                       tx.sink.data.eq(primitives["ALIGN"]),
-                                       tx.sink.charisk.eq(0b0001),
-                                       self.sink.ack.eq(0)
-                               ).Else(
-                                       tx.sink.stb.eq(self.sink.stb),
-                                       tx.sink.data.eq(self.sink.data),
-                                       tx.sink.charisk.eq(self.sink.charisk),
-                                       self.sink.ack.eq(tx.sink.ack)
-                               ),
-                               If(receive_align,
-                                       rx.source.ack.eq(1)
-                               ).Else(
-                                       self.source.stb.eq(rx.source.stb),
-                                       self.source.data.eq(rx.source.data),
-                                       self.source.charisk.eq(rx.source.charisk),
-                                       rx.source.ack.eq(1)
-                               )
-                       # ctrl
-                       ).Else(
-                               tx.sink.stb.eq(ctrl.source.stb),
-                               tx.sink.data.eq(ctrl.source.data),
-                               tx.sink.charisk.eq(ctrl.source.charisk),
-
-                               ctrl.sink.stb.eq(rx.source.stb),
-                               ctrl.sink.data.eq(rx.source.data),
-                               rx.source.ack.eq(1),
-                       )
+                       self.demux.sel.eq(ctrl.ready),
+                       Record.connect(trx.source, self.rx.sink),
+                       Record.connect(self.rx.source, self.demux.sink),
+                       Record.connect(self.demux.source0, ctrl.sink),
+                       Record.connect(self.demux.source1, self.align_remover.sink),
+                       Record.connect(self.align_remover.source, self.source)
                ]
index cfdd7214abde957eee4b2f91368d1c923724546d..0285918229121e4af59108823dc59f29ddf4d0e1 100644 (file)
@@ -6,6 +6,9 @@ CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
 CC=gcc
 CFLAGS =-Wall -O0
 
+phy_datapath_tb:
+       $(CMD) phy_datapath_tb.py
+
 crc_tb:
        $(CC) $(CFLAGS) $(INC) -o crc crc.c
        $(CMD) crc_tb.py
diff --git a/lib/sata/test/phy_datapath_tb.py b/lib/sata/test/phy_datapath_tb.py
new file mode 100644 (file)
index 0000000..6967213
--- /dev/null
@@ -0,0 +1,88 @@
+from lib.sata.common import *
+from lib.sata.phy.datapath import SATAPHYDatapath
+
+from lib.sata.test.common import *
+
+class DataPacket(list):
+       def __init__(self, data=[]):
+               self.ongoing = False
+               self.done = False
+               for d in data:
+                       self.append(d)
+
+class DataStreamer(PacketStreamer):
+       def __init__(self):
+               PacketStreamer.__init__(self, phy_description(32), DataPacket)
+
+       def do_simulation(self, selfp):
+               PacketStreamer.do_simulation(self, selfp)
+               selfp.source.charisk = 0
+               # Note: for simplicity we generate charisk by detecting
+               # primitives in data
+               for k, v in primitives.items():
+                       try:
+                               if self.source_data == v:
+                                       selfp.source.charisk = 0b0001
+                       except:
+                               pass
+
+class DataLogger(PacketLogger):
+       def __init__(self):
+               PacketLogger.__init__(self, phy_description(32), DataPacket)
+
+class TRX(Module):
+       def __init__(self):
+               self.sink = Sink(phy_description(32))
+               self.source = Source(phy_description(32))
+               self.comb += Record.connect(self.sink, self.source)
+
+class CTRL(Module):
+       def __init__(self):
+               self.sink = Sink(phy_description(32))
+               self.source = Source(phy_description(32))
+               self.ready = Signal(reset=1)
+
+class TB(Module):
+       def __init__(self):
+               # use sys_clk for each clock_domain
+               self.clock_domains.cd_sata_rx = ClockDomain()
+               self.clock_domains.cd_sata_tx = ClockDomain()
+               self.comb += [
+                       self.cd_sata_rx.clk.eq(ClockSignal()),
+                       self.cd_sata_rx.rst.eq(ResetSignal()),
+                       self.cd_sata_tx.clk.eq(ClockSignal()),
+                       self.cd_sata_tx.rst.eq(ResetSignal()),
+               ]
+
+               self.streamer = DataStreamer()
+               self.streamer_randomizer = Randomizer(phy_description(32), level=0)
+               self.trx = TRX()
+               self.ctrl = CTRL()
+               self.datapath = SATAPHYDatapath(self.trx, self.ctrl)
+               self.logger_randomizer = Randomizer(phy_description(32), level=0)
+               self.logger = DataLogger()
+
+               self.pipeline = Pipeline(
+                       self.streamer,
+                       self.streamer_randomizer,
+                       self.datapath,
+                       self.logger_randomizer,
+                       self.logger
+               )
+
+       def gen_simulation(self, selfp):
+               streamer_packet = DataPacket([seed_to_data(i, False) for i in range(512)])
+               yield from self.streamer.send(streamer_packet)
+               yield from self.logger.receive(512)
+               for d in self.logger.packet:
+                       r = "%08x " %d
+                       r +=decode_primitive(d)
+                       print(r)
+
+               # check results
+               #s, l, e = check(streamer_packet, self.logger.packet)
+               #print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+
+if __name__ == "__main__":
+       run_simulation(TB(), ncycles=4096, vcd_name="my.vcd", keep_files=True)