refactor code
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 16 Jan 2015 22:52:41 +0000 (23:52 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Sat, 17 Jan 2015 12:22:52 +0000 (13:22 +0100)
68 files changed:
Makefile
README
lib/sata/__init__.py [deleted file]
lib/sata/bist.py [deleted file]
lib/sata/command/__init__.py [deleted file]
lib/sata/common.py [deleted file]
lib/sata/frontend/arbiter.py [deleted file]
lib/sata/frontend/common.py [deleted file]
lib/sata/frontend/crossbar.py [deleted file]
lib/sata/link/__init__.py [deleted file]
lib/sata/link/cont.py [deleted file]
lib/sata/link/crc.py [deleted file]
lib/sata/link/scrambler.py [deleted file]
lib/sata/phy/__init__.py [deleted file]
lib/sata/phy/ctrl.py [deleted file]
lib/sata/phy/datapath.py [deleted file]
lib/sata/phy/k7/crg.py [deleted file]
lib/sata/phy/k7/trx.py [deleted file]
lib/sata/test/Makefile [deleted file]
lib/sata/test/bist_tb.py [deleted file]
lib/sata/test/command_tb.py [deleted file]
lib/sata/test/common.py [deleted file]
lib/sata/test/cont_tb.py [deleted file]
lib/sata/test/crc.c [deleted file]
lib/sata/test/crc_tb.py [deleted file]
lib/sata/test/hdd.py [deleted file]
lib/sata/test/link_tb.py [deleted file]
lib/sata/test/phy_datapath_tb.py [deleted file]
lib/sata/test/scrambler.c [deleted file]
lib/sata/test/scrambler_tb.py [deleted file]
lib/sata/transport/__init__.py [deleted file]
litesata/__init__.py [new file with mode: 0644]
litesata/common.py [new file with mode: 0644]
litesata/core/__init__.py [new file with mode: 0644]
litesata/core/command/__init__.py [new file with mode: 0644]
litesata/core/link/__init__.py [new file with mode: 0644]
litesata/core/link/cont.py [new file with mode: 0644]
litesata/core/link/crc.py [new file with mode: 0644]
litesata/core/link/scrambler.py [new file with mode: 0644]
litesata/core/transport/__init__.py [new file with mode: 0644]
litesata/frontend/__init__.py [new file with mode: 0644]
litesata/frontend/arbiter.py [new file with mode: 0644]
litesata/frontend/bist.py [new file with mode: 0644]
litesata/frontend/common.py [new file with mode: 0644]
litesata/frontend/crossbar.py [new file with mode: 0644]
litesata/phy/__init__.py [new file with mode: 0644]
litesata/phy/ctrl.py [new file with mode: 0644]
litesata/phy/datapath.py [new file with mode: 0644]
litesata/phy/k7/crg.py [new file with mode: 0644]
litesata/phy/k7/trx.py [new file with mode: 0644]
litesata/test/Makefile [new file with mode: 0644]
litesata/test/bist_tb.py [new file with mode: 0644]
litesata/test/command_tb.py [new file with mode: 0644]
litesata/test/common.py [new file with mode: 0644]
litesata/test/cont_tb.py [new file with mode: 0644]
litesata/test/crc.c [new file with mode: 0644]
litesata/test/crc_tb.py [new file with mode: 0644]
litesata/test/hdd.py [new file with mode: 0644]
litesata/test/link_tb.py [new file with mode: 0644]
litesata/test/phy_datapath_tb.py [new file with mode: 0644]
litesata/test/scrambler.c [new file with mode: 0644]
litesata/test/scrambler_tb.py [new file with mode: 0644]
platforms/kc705.py
setup.py [new file with mode: 0644]
targets/bist.py [deleted file]
targets/bist_kc705.py [new file with mode: 0644]
test/bist.py
test/test_link.py

index deb3bd82318233212314720848eb78cd7bccf251..5a3406d1e46e33f7c7c8f66dd4f8818fc6cfafa9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,10 +2,9 @@ MSCDIR = ../misoc
 CURDIR = ../lite-sata
 PYTHON = python3
 TOOLCHAIN = vivado
-PLATFORM = kc705
 PROGRAMMER = vivado
 
-CMD = $(PYTHON) make.py -X $(CURDIR) -Op toolchain $(TOOLCHAIN) -Op programmer $(PROGRAMMER) -p $(PLATFORM) -t bist
+CMD = $(PYTHON) make.py -X $(CURDIR) -Op toolchain $(TOOLCHAIN) -Op programmer $(PROGRAMMER) -t bist_kc705
 
 csv:
        cd $(MSCDIR) && $(CMD) --csr_csv $(CURDIR)/test/csr.csv build-csr-csv -Ot export_mila True
diff --git a/README b/README
index 215829a77a47ff479b02b3d8401d6bfd2e2c6c27..df0e9b63eabaa9d515a8c6be8384f298206aee06 100644 (file)
--- a/README
+++ b/README
@@ -5,8 +5,35 @@
 
         Copyright 2014-2015 / Florent Kermarrec / florent@enjoy-digital.fr
 
-                A lite open-source SATA1/2/3 controller
-            developed in partnership with M-Labs Ltd & HKU
+                A generic and configurable SATA1/2/3 core
+              developed in partnership with M-Labs Ltd & HKU
+
+[> Features
+------------------
+PHY:
+  - OOB, COMWAKE, COMINIT.
+  - ALIGN inserter/remover and bytes alignment on K28.5.
+  - 8B/10B encoding/decoding in transceiver.
+  - Errors detection and reporting.
+  - 1.5  / 3.0 / 6.0GBPs supported speeds.
+  - 37.5 /  75 / 150MHz system clock.
+Core:
+  Link:
+    - CONT inserter/remover.
+    - Scrambling/Descrambling of data.
+    - CRC inserter/checker.
+    - HOLD insertion/detection.
+    - Errors detection and reporting.
+  Transport/Command:
+    - Easy to use user interface (Can be used with or without CPU).
+    - 48 bits sector addressing.
+    - 3 supported commands: READ_DMA(_EXT), WRITE_DMA(_EXT), IDENTIFY_DEVICE.
+    - Errors detection and reporting.
+
+Frontend:
+  - Configurable crossbar (simply use core.crossbar.get_port() to add a new port!)
+  - Ports arbitration transparent to the user.
+  - Synthetizable BIST.
 
 [> Getting started
 ------------------
   make all
 
 7. Test design:
-  go to test directory
+  go to test directory and run:
   python3 bist.py
 
 [> Simulations :
-  Simulation are avalaible in ./lib/sata/test:
+  Simulations are avalaible in ./lib/sata/test:
     - crc_tb
     - scrambler_tb
     - phy_datapath_tb
     - command_tb
     - bist_tb
   hdd.py is a HDD model implementing all SATA layers.
-  To run a simulation, move to the simulation directory and run:
+  To run a simulation, move to ./lib/sata/test and run:
     make simulation_name
 
 [> Tests :
-  A synthetisable BIST is provided. It can be controled with ./test/bist.py
-  Using Miscope and the provided example ./test/test_link.py you are able to
-  visualize every event of the design and even inject your data in the HDD
-  model!
+  A synthetisable BIST is provided and can be controlled with ./test/bist.py
+  By using Miscope and the provided ./test/test_link.py example you are able to
+  visualize the internal logic of the design and even inject the captured data in
+  the HDD model!
 
 [> Contact
 E-mail: florent@enjoy-digital.fr
diff --git a/lib/sata/__init__.py b/lib/sata/__init__.py
deleted file mode 100644 (file)
index 0a167bd..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-from lib.sata.common import *
-from lib.sata.link import SATALink
-from lib.sata.transport import SATATransport
-from lib.sata.command import SATACommand
-
-from lib.sata.frontend.crossbar import SATACrossbar
-
-class SATACON(Module):
-       def __init__(self, phy):
-               ###
-               # core
-               self.link = SATALink(phy)
-               self.transport = SATATransport(self.link)
-               self.command = SATACommand(self.transport)
-
-               # frontend
-               self.crossbar = SATACrossbar(32)
-               self.comb += [
-                       Record.connect(self.crossbar.master.source, self.command.sink),
-                       Record.connect(self.command.source, self.crossbar.master.sink)
-               ]
diff --git a/lib/sata/bist.py b/lib/sata/bist.py
deleted file mode 100644 (file)
index 4dfba89..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-from lib.sata.common import *
-from lib.sata.link.scrambler import Scrambler
-
-from migen.fhdl.decorators import ModuleDecorator
-from migen.bank.description import *
-
-class SATABISTGenerator(Module):
-       def __init__(self, sata_master_port):
-               self.start = Signal()
-               self.sector = Signal(48)
-               self.count = Signal(16)
-               self.random = Signal()
-
-               self.done = Signal()
-               self.errors = Signal(32) # Note: Not used for writes
-
-               ###
-
-               source, sink = sata_master_port.source, sata_master_port.sink
-
-               self.counter = counter = Counter(bits_sign=32)
-
-               self.scrambler = scrambler = InsertReset(Scrambler())
-               self.comb += [
-                       scrambler.reset.eq(counter.reset),
-                       scrambler.ce.eq(counter.ce)
-               ]
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-               fsm.act("IDLE",
-                       self.done.eq(1),
-                       counter.reset.eq(1),
-                       If(self.start,
-                               NextState("SEND_CMD_AND_DATA")
-                       )
-               )
-               self.comb += [
-                       source.sop.eq(counter.value == 0),
-                       source.eop.eq(counter.value == (logical_sector_size//4*self.count)-1),
-                       source.write.eq(1),
-                       source.sector.eq(self.sector),
-                       source.count.eq(self.count),
-                       If(self.random,
-                               source.data.eq(scrambler.value)
-                       ).Else(
-                               source.data.eq(counter.value)
-                       )
-               ]
-               fsm.act("SEND_CMD_AND_DATA",
-                       source.stb.eq(1),
-                       If(source.stb & source.ack,
-                               counter.ce.eq(1),
-                               If(source.eop,
-                                       NextState("WAIT_ACK")
-                               )
-                       )
-               )
-               fsm.act("WAIT_ACK",
-                       sink.ack.eq(1),
-                       If(sink.stb,
-                               NextState("IDLE")
-                       )
-               )
-
-class SATABISTChecker(Module):
-       def __init__(self, sata_master_port):
-               self.start = Signal()
-               self.sector = Signal(48)
-               self.count = Signal(16)
-               self.random = Signal()
-
-               self.done = Signal()
-               self.errors = Signal(32)
-
-               ###
-
-               source, sink = sata_master_port.source, sata_master_port.sink
-
-               self.counter = counter = Counter(bits_sign=32)
-               self.error_counter = Counter(self.errors, bits_sign=32)
-
-               self.scrambler = scrambler = InsertReset(Scrambler())
-               self.comb += [
-                       scrambler.reset.eq(counter.reset),
-                       scrambler.ce.eq(counter.ce)
-               ]
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-               fsm.act("IDLE",
-                       self.done.eq(1),
-                       counter.reset.eq(1),
-                       If(self.start,
-                               self.error_counter.reset.eq(1),
-                               NextState("SEND_CMD")
-                       )
-               )
-               self.comb += [
-                       source.sop.eq(1),
-                       source.eop.eq(1),
-                       source.read.eq(1),
-                       source.sector.eq(self.sector),
-                       source.count.eq(self.count),
-               ]
-               fsm.act("SEND_CMD",
-                       source.stb.eq(1),
-                       If(source.ack,
-                               counter.reset.eq(1),
-                               NextState("WAIT_ACK")
-                       )
-               )
-               fsm.act("WAIT_ACK",
-                       If(sink.stb & sink.read,
-                               NextState("RECEIVE_DATA")
-                       )
-               )
-               expected_data = Signal(32)
-               self.comb += \
-                       If(self.random,
-                               expected_data.eq(scrambler.value)
-                       ).Else(
-                               expected_data.eq(counter.value)
-                       )
-               fsm.act("RECEIVE_DATA",
-                       sink.ack.eq(1),
-                       If(sink.stb,
-                               counter.ce.eq(1),
-                               If(sink.data != expected_data,
-                                       self.error_counter.ce.eq(1)
-                               ),
-                               If(sink.eop,
-                                       If(sink.last,
-                                               NextState("IDLE")
-                                       ).Else(
-                                               NextState("WAIT_ACK")
-                                       )
-                               )
-                       )
-               )
-
-class SATABISTUnitControl(Module, AutoCSR):
-       def __init__(self, bist_unit):
-               self._start = CSR()
-               self._sector = CSRStorage(48)
-               self._count = CSRStorage(16)
-               self._random = CSRStorage()
-               self._done = CSRStatus()
-               self._errors = CSRStatus(32)
-               self._cycles = CSRStatus(32)
-
-               ###
-               self.bist_unit = bist_unit
-               self.comb += [
-                       bist_unit.start.eq(self._start.r & self._start.re),
-                       bist_unit.sector.eq(self._sector.storage),
-                       bist_unit.count.eq(self._count.storage),
-                       bist_unit.random.eq(self._random.storage),
-
-                       self._done.status.eq(bist_unit.done),
-                       self._errors.status.eq(bist_unit.errors)
-               ]
-
-               self.cycles_counter = Counter(self._cycles.status)
-               self.sync += [
-                       self.cycles_counter.reset.eq(bist_unit.start),
-                       self.cycles_counter.ce.eq(~bist_unit.done)
-               ]
-
-class SATABISTIdentify(Module):
-       def __init__(self, sata_master_port):
-               self.start = Signal()
-               self.done  = Signal()
-
-               self.fifo = fifo = SyncFIFO([("data", 32)], 512, buffered=True)
-               self.source = self.fifo.source
-
-               ###
-
-               source, sink = sata_master_port.source, sata_master_port.sink
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-               fsm.act("IDLE",
-                       self.done.eq(1),
-                       If(self.start,
-                               NextState("SEND_CMD")
-                       )
-               )
-               self.comb += [
-                       source.sop.eq(1),
-                       source.eop.eq(1),
-                       source.identify.eq(1),
-               ]
-               fsm.act("SEND_CMD",
-                       source.stb.eq(1),
-                       If(source.stb & source.ack,
-                               NextState("WAIT_ACK")
-                       )
-               )
-               fsm.act("WAIT_ACK",
-                       If(sink.stb & sink.identify,
-                               NextState("RECEIVE_DATA")
-                       )
-               )
-               self.comb += fifo.sink.data.eq(sink.data)
-               fsm.act("RECEIVE_DATA",
-                       sink.ack.eq(fifo.sink.ack),
-                       If(sink.stb,
-                               fifo.sink.stb.eq(1),
-                               If(sink.eop,
-                                       NextState("IDLE")
-                               )
-                       )
-               )
-
-class SATABISTIdentifyControl(Module, AutoCSR):
-       def __init__(self, bist_identify):
-               self._start = CSR()
-               self._done = CSRStatus()
-               self._source_stb = CSRStatus()
-               self._source_ack = CSR()
-               self._source_data = CSRStatus(32)
-
-               ###
-               self.bist_identify = bist_identify
-               self.comb += [
-                       bist_identify.start.eq(self._start.r & self._start.re),
-                       self._done.status.eq(bist_identify.done),
-
-                       self._source_stb.status.eq(bist_identify.source.stb),
-                       self._source_data.status.eq(bist_identify.source.data),
-                       bist_identify.source.ack.eq(self._source_ack.r & self._source_ack.re)
-               ]
-
-class SATABIST(Module, AutoCSR):
-       def __init__(self, sata_master_ports, with_control=False):
-               generator = SATABISTGenerator(sata_master_ports[0])
-               checker = SATABISTChecker(sata_master_ports[1])
-               identify = SATABISTIdentify(sata_master_ports[2])
-               if with_control:
-                       self.generator = SATABISTUnitControl(generator)
-                       self.checker = SATABISTUnitControl(checker)
-                       self.identify = SATABISTIdentifyControl(identify)
-               else:
-                       self.generator = generator
-                       self.checker = checker
-                       self.identify = identify
diff --git a/lib/sata/command/__init__.py b/lib/sata/command/__init__.py
deleted file mode 100644 (file)
index 810d235..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-from lib.sata.common import *
-
-tx_to_rx = [
-       ("write", 1),
-       ("read", 1),
-       ("identify", 1),
-       ("count", 16)
-]
-
-rx_to_tx = [
-       ("dma_activate", 1)
-]
-
-class SATACommandTX(Module):
-       def __init__(self, transport):
-               self.sink = sink = Sink(command_tx_description(32))
-               self.to_rx = to_rx = Source(tx_to_rx)
-               self.from_rx = from_rx = Sink(rx_to_tx)
-
-               ###
-
-               self.comb += [
-                       transport.sink.pm_port.eq(0),
-                       transport.sink.features.eq(0),
-                       transport.sink.lba.eq(sink.sector),
-                       transport.sink.device.eq(0xe0),
-                       transport.sink.count.eq(sink.count),
-                       transport.sink.icc.eq(0),
-                       transport.sink.control.eq(0),
-                       transport.sink.data.eq(sink.data)
-               ]
-
-               self.dwords_counter = dwords_counter = Counter(max=fis_max_dwords)
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-               fsm.act("IDLE",
-                       sink.ack.eq(0),
-                       If(sink.stb & sink.sop,
-                               If(sink.write,
-                                       NextState("SEND_WRITE_DMA_CMD")
-                               ).Elif(sink.read,
-                                       NextState("SEND_READ_DMA_CMD")
-                               ).Elif(sink.identify,
-                                       NextState("SEND_IDENTIFY_CMD")
-                               ).Else(
-                                       sink.ack.eq(1)
-                               )
-                       ).Else(
-                               sink.ack.eq(1)
-                       )
-               )
-               fsm.act("SEND_WRITE_DMA_CMD",
-                       transport.sink.stb.eq(sink.stb),
-                       transport.sink.sop.eq(1),
-                       transport.sink.eop.eq(1),
-                       transport.sink.type.eq(fis_types["REG_H2D"]),
-                       transport.sink.c.eq(1),
-                       transport.sink.command.eq(regs["WRITE_DMA_EXT"]),
-                       If(sink.stb & transport.sink.ack,
-                               NextState("WAIT_DMA_ACTIVATE")
-                       )
-               )
-               fsm.act("WAIT_DMA_ACTIVATE",
-                       dwords_counter.reset.eq(1),
-                       If(from_rx.dma_activate,
-                               NextState("SEND_DATA")
-                       )
-               )
-               fsm.act("SEND_DATA",
-                       dwords_counter.ce.eq(sink.stb & sink.ack),
-
-                       transport.sink.stb.eq(sink.stb),
-                       transport.sink.sop.eq(dwords_counter.value == 0),
-                       transport.sink.eop.eq((dwords_counter.value == (fis_max_dwords-1)) | sink.eop),
-
-                       transport.sink.type.eq(fis_types["DATA"]),
-                       sink.ack.eq(transport.sink.ack),
-                       If(sink.stb & sink.ack,
-                               If(sink.eop,
-                                       NextState("IDLE")
-                               ).Elif(dwords_counter.value == (fis_max_dwords-1),
-                                       NextState("WAIT_DMA_ACTIVATE")
-                               )
-                       )
-               )
-               fsm.act("SEND_READ_DMA_CMD",
-                       transport.sink.stb.eq(sink.stb),
-                       transport.sink.sop.eq(1),
-                       transport.sink.eop.eq(1),
-                       transport.sink.type.eq(fis_types["REG_H2D"]),
-                       transport.sink.c.eq(1),
-                       transport.sink.command.eq(regs["READ_DMA_EXT"]),
-                       sink.ack.eq(transport.sink.ack),
-                       If(sink.stb & sink.ack,
-                               NextState("IDLE")
-                       )
-               )
-               fsm.act("SEND_IDENTIFY_CMD",
-                       transport.sink.stb.eq(sink.stb),
-                       transport.sink.sop.eq(1),
-                       transport.sink.eop.eq(1),
-                       transport.sink.type.eq(fis_types["REG_H2D"]),
-                       transport.sink.c.eq(1),
-                       transport.sink.command.eq(regs["IDENTIFY_DEVICE"]),
-                       sink.ack.eq(transport.sink.ack),
-                       If(sink.stb & sink.ack,
-                               NextState("IDLE")
-                       )
-               )
-
-               self.comb += [
-                       If(sink.stb,
-                               to_rx.write.eq(sink.write),
-                               to_rx.read.eq(sink.read),
-                               to_rx.identify.eq(sink.identify),
-                               to_rx.count.eq(sink.count)
-                       )
-               ]
-
-class SATACommandRX(Module):
-       def __init__(self, transport):
-               self.source = source = Source(command_rx_description(32))
-               self.to_tx = to_tx = Source(rx_to_tx)
-               self.from_tx = from_tx = Sink(tx_to_rx)
-
-               ###
-
-               cmd_buffer = Buffer(command_rx_cmd_description(32))
-               cmd_buffer.sink, cmd_buffer.source = cmd_buffer.d, cmd_buffer.q
-               data_buffer = InsertReset(SyncFIFO(command_rx_data_description(32), fis_max_dwords, buffered=True))
-               self.submodules += cmd_buffer, data_buffer
-
-               def test_type(name):
-                       return transport.source.type == fis_types[name]
-
-               identify = Signal()
-               dma_activate = Signal()
-               read_ndwords = Signal(max=sectors2dwords(2**16))
-               self.dwords_counter = dwords_counter = Counter(max=sectors2dwords(2**16))
-               read_done = Signal()
-
-               self.sync += \
-                       If(from_tx.read,
-                               read_ndwords.eq(from_tx.count*sectors2dwords(1)-1)
-                       )
-               self.comb += read_done.eq(self.dwords_counter.value == read_ndwords)
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-               fsm.act("IDLE",
-                       self.dwords_counter.reset.eq(1),
-                       transport.source.ack.eq(1),
-                       If(from_tx.write,
-                               NextState("WAIT_WRITE_ACTIVATE_OR_REG_D2H")
-                       ).Elif(from_tx.read,
-                               NextState("WAIT_READ_DATA_OR_REG_D2H"),
-                       ).Elif(from_tx.identify,
-                               NextState("WAIT_PIO_SETUP_D2H"),
-                       )
-               )
-               self.sync += \
-                       If(fsm.ongoing("IDLE"),
-                               identify.eq(from_tx.identify)
-                       )
-               fsm.act("WAIT_WRITE_ACTIVATE_OR_REG_D2H",
-                       transport.source.ack.eq(1),
-                       If(transport.source.stb,
-                               If(test_type("DMA_ACTIVATE_D2H"),
-                                       dma_activate.eq(1),
-                               ).Elif(test_type("REG_D2H"),
-                                       # XXX: use status and error fields of REG_D2H
-                                       NextState("PRESENT_WRITE_RESPONSE")
-                               )
-                       )
-               )
-               fsm.act("PRESENT_WRITE_RESPONSE",
-                       cmd_buffer.sink.stb.eq(1),
-                       cmd_buffer.sink.write.eq(1),
-                       cmd_buffer.sink.last.eq(1),
-                       cmd_buffer.sink.success.eq(~transport.source.error),
-                       cmd_buffer.sink.failed.eq(transport.source.error),
-                       If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
-                               NextState("IDLE")
-                       )
-               )
-               fsm.act("WAIT_READ_DATA_OR_REG_D2H",
-                       transport.source.ack.eq(1),
-                       If(transport.source.stb,
-                               transport.source.ack.eq(0),
-                               If(test_type("DATA"),
-                                       NextState("PRESENT_READ_DATA")
-                               ).Elif(test_type("REG_D2H"),
-                                       # XXX: use status and error fields of REG_D2H
-                                       NextState("PRESENT_READ_RESPONSE")
-                               )
-                       )
-               )
-               fsm.act("WAIT_PIO_SETUP_D2H",
-                       transport.source.ack.eq(1),
-                       If(transport.source.stb,
-                               transport.source.ack.eq(0),
-                               If(test_type("PIO_SETUP_D2H"),
-                                       NextState("PRESENT_PIO_SETUP_D2H")
-                               )
-                       )
-               )
-               fsm.act("PRESENT_PIO_SETUP_D2H",
-                       transport.source.ack.eq(1),
-                       # XXX : Check error/ status
-                       If(transport.source.stb & transport.source.eop,
-                               NextState("WAIT_READ_DATA_OR_REG_D2H")
-                       )
-               )
-
-               self.comb += [
-                       data_buffer.sink.sop.eq(transport.source.sop),
-                       data_buffer.sink.eop.eq(transport.source.eop),
-                       data_buffer.sink.data.eq(transport.source.data)
-               ]
-               fsm.act("PRESENT_READ_DATA",
-                       data_buffer.sink.stb.eq(transport.source.stb),
-                       transport.source.ack.eq(data_buffer.sink.ack),
-                       If(data_buffer.sink.stb & data_buffer.sink.ack,
-                               self.dwords_counter.ce.eq(~read_done),
-                               If(data_buffer.sink.eop,
-                                       If(read_done & ~identify,
-                                               NextState("WAIT_READ_DATA_OR_REG_D2H")
-                                       ).Else(
-                                               NextState("PRESENT_READ_RESPONSE")
-                                       )
-                               )
-                       )
-               )
-               read_error = Signal()
-               self.sync += \
-                       If(fsm.before_entering("PRESENT_READ_DATA"),
-                               read_error.eq(1)
-                       ).Elif(transport.source.stb & transport.source.ack & transport.source.eop,
-                               read_error.eq(transport.source.error)
-                       )
-               fsm.act("PRESENT_READ_RESPONSE",
-                       cmd_buffer.sink.stb.eq(1),
-                       cmd_buffer.sink.read.eq(~identify),
-                       cmd_buffer.sink.identify.eq(identify),
-                       cmd_buffer.sink.last.eq(read_done | identify),
-                       cmd_buffer.sink.success.eq(~read_error),
-                       cmd_buffer.sink.failed.eq(read_error),
-                       If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
-                               If(cmd_buffer.sink.failed,
-                                       data_buffer.reset.eq(1)
-                               ),
-                               If(read_done | identify,
-                                       NextState("IDLE")
-                               ).Else(
-                                       NextState("WAIT_READ_DATA_OR_REG_D2H")
-                               )
-                       )
-               )
-
-               self.out_fsm = out_fsm = FSM(reset_state="IDLE")
-               out_fsm.act("IDLE",
-                       If(cmd_buffer.source.stb,
-                               If((cmd_buffer.source.read | cmd_buffer.source.identify) & cmd_buffer.source.success,
-                                       NextState("PRESENT_RESPONSE_WITH_DATA"),
-                               ).Else(
-                                       NextState("PRESENT_RESPONSE_WITHOUT_DATA"),
-                               )
-                       )
-               )
-
-               self.comb += [
-                       source.write.eq(cmd_buffer.source.write),
-                       source.read.eq(cmd_buffer.source.read),
-                       source.identify.eq(cmd_buffer.source.identify),
-                       source.last.eq(cmd_buffer.source.last),
-                       source.success.eq(cmd_buffer.source.success),
-                       source.failed.eq(cmd_buffer.source.failed),
-                       source.data.eq(data_buffer.source.data)
-               ]
-
-               out_fsm.act("PRESENT_RESPONSE_WITH_DATA",
-                       source.stb.eq(data_buffer.source.stb),
-                       source.sop.eq(data_buffer.source.sop),
-                       source.eop.eq(data_buffer.source.eop),
-
-                       data_buffer.source.ack.eq(source.ack),
-
-                       If(source.stb & source.eop & source.ack,
-                               cmd_buffer.source.ack.eq(1),
-                               NextState("IDLE")
-                       )
-               )
-               out_fsm.act("PRESENT_RESPONSE_WITHOUT_DATA",
-                       source.stb.eq(1),
-                       source.sop.eq(1),
-                       source.eop.eq(1),
-                       If(source.stb & source.ack,
-                               cmd_buffer.source.ack.eq(1),
-                               NextState("IDLE")
-                       )
-               )
-
-               self.comb += [
-                       to_tx.dma_activate.eq(dma_activate),
-               ]
-
-class SATACommand(Module):
-       def __init__(self, transport):
-               self.tx = SATACommandTX(transport)
-               self.rx = SATACommandRX(transport)
-               self.comb += [
-                       self.rx.to_tx.connect(self.tx.from_rx),
-                       self.tx.to_rx.connect(self.rx.from_tx)
-               ]
-               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/lib/sata/common.py b/lib/sata/common.py
deleted file mode 100644 (file)
index bce3b57..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-import math
-
-from migen.fhdl.std import *
-from migen.genlib.resetsync import *
-from migen.genlib.fsm import *
-from migen.genlib.record import *
-from migen.flow.actor import *
-from migen.flow.plumbing import Buffer
-from migen.actorlib.fifo import *
-from migen.actorlib.structuring import Pipeline
-
-# PHY / Link Layers
-primitives = {
-       "ALIGN" :       0x7B4A4ABC,
-       "CONT"  :       0X9999AA7C,
-       "SYNC"  :       0xB5B5957C,
-       "R_RDY" :       0x4A4A957C,
-       "R_OK"  :       0x3535B57C,
-       "R_ERR" :       0x5656B57C,
-       "R_IP"  :       0X5555B57C,
-       "X_RDY" :       0x5757B57C,
-       "CONT"  :       0x9999AA7C,
-       "WTRM"  :       0x5858B57C,
-       "SOF"   :       0x3737B57C,
-       "EOF"   :       0xD5D5B57C,
-       "HOLD"  :       0xD5D5AA7C,
-       "HOLDA" :       0X9595AA7C
-}
-
-def is_primitive(dword):
-       for k, v in primitives.items():
-               if dword == v:
-                       return True
-       return False
-
-def decode_primitive(dword):
-       for k, v in primitives.items():
-               if dword == v:
-                       return k
-       return ""
-
-def phy_description(dw):
-       layout = [
-               ("data", dw),
-               ("charisk", dw//8),
-       ]
-       return EndpointDescription(layout, packetized=False)
-
-def link_description(dw):
-       layout = [
-               ("d", dw),
-               ("error", 1)
-       ]
-       return EndpointDescription(layout, packetized=True)
-
-# Transport Layer
-fis_max_dwords = 2048
-
-fis_types = {
-       "REG_H2D":          0x27,
-       "REG_D2H":          0x34,
-       "DMA_ACTIVATE_D2H": 0x39,
-       "PIO_SETUP_D2H":        0x5F,
-       "DATA":             0x46
-}
-
-class FISField():
-       def __init__(self, dword, offset, width):
-               self.dword = dword
-               self.offset = offset
-               self.width = width
-
-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_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)
-}
-
-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),
-
-       "lba_lsb": FISField(1, 0, 24),
-       "device":  FISField(1, 24, 8),
-
-       "lba_msb": FISField(2, 0, 24),
-
-       "count":   FISField(3, 0, 16)
-}
-
-fis_dma_activate_d2h_cmd_len = 1
-fis_dma_activate_d2h_layout = {
-       "type":    FISField(0,  0, 8),
-       "pm_port": FISField(0,  8, 4)
-}
-
-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),
-
-       "lba_lsb": FISField(1, 0, 24),
-
-       "lba_msb": FISField(2, 0, 24),
-
-       "count":   FISField(3, 0, 16),
-
-       "transfer_count":       FISField(4, 0, 16),
-}
-
-fis_data_cmd_len = 1
-fis_data_layout = {
-       "type": FISField(0,  0, 8)
-}
-
-def transport_tx_description(dw):
-       layout = [
-               ("type", 8),
-               ("pm_port", 4),
-               ("c", 1),
-               ("command", 8),
-               ("features", 16),
-               ("lba", 48),
-               ("device", 8),
-               ("count", 16),
-               ("icc", 8),
-               ("control", 8),
-               ("data", dw)
-       ]
-       return EndpointDescription(layout, packetized=True)
-
-def transport_rx_description(dw):
-       layout = [
-               ("type", 8),
-               ("pm_port", 4),
-               ("r", 1),
-               ("d", 1),
-               ("i", 1),
-               ("status", 8),
-               ("error", 8),
-               ("lba", 48),
-               ("device", 8),
-               ("count", 16),
-               ("transfer_count", 16),
-               ("data", dw),
-               ("error", 1)
-       ]
-       return EndpointDescription(layout, packetized=True)
-
-# Command Layer
-regs = {
-       "WRITE_DMA_EXT"                 : 0x35,
-       "READ_DMA_EXT"                  : 0x25,
-       "IDENTIFY_DEVICE"               : 0xEC
-}
-
-def command_tx_description(dw):
-       layout = [
-               ("write", 1),
-               ("read", 1),
-               ("identify", 1),
-               ("sector", 48),
-               ("count", 16),
-               ("data", dw)
-       ]
-       return EndpointDescription(layout, packetized=True)
-
-def command_rx_description(dw):
-       layout = [
-               ("write", 1),
-               ("read", 1),
-               ("identify", 1),
-               ("last", 1),
-               ("success", 1),
-               ("failed", 1),
-               ("data", dw)
-       ]
-       return EndpointDescription(layout, packetized=True)
-
-def command_rx_cmd_description(dw):
-       layout = [
-               ("write", 1),
-               ("read", 1),
-               ("identify", 1),
-               ("last", 1),
-               ("success", 1),
-               ("failed", 1)
-       ]
-       return EndpointDescription(layout, packetized=False)
-
-def command_rx_data_description(dw):
-       layout = [
-               ("data", dw)
-       ]
-       return EndpointDescription(layout, packetized=True)
-
-# HDD
-logical_sector_size = 512 # constant since all HDDs use this
-
-def dwords2sectors(n):
-       return math.ceil(n*4/logical_sector_size)
-
-def sectors2dwords(n):
-       return n*logical_sector_size//4
-
-# Generic modules
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class Counter(Module):
-       def __init__(self, signal=None, **kwargs):
-               if signal is None:
-                       self.value = Signal(**kwargs)
-               else:
-                       self.value = signal
-               self.width = flen(self.value)
-               self.sync += self.value.eq(self.value+1)
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class Timeout(Module):
-       def __init__(self, length):
-               self.reached = Signal()
-               ###
-               value = Signal(max=length)
-               self.sync += value.eq(value+1)
-               self.comb += [
-                       self.reached.eq(value == length)
-               ]
-
-# XXX use ModuleDecorator
-class BufferizeEndpoints(Module):
-       def __init__(self, decorated, *args):
-               self.decorated = decorated
-
-               endpoints = get_endpoints(decorated)
-               sinks = {}
-               sources = {}
-               for name, endpoint in endpoints.items():
-                       if name in args or len(args) == 0:
-                               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)
-                       self.submodules += buf
-                       setattr(self, name, buf.d)
-                       self.comb += Record.connect(buf.q, sink)
-
-               # add buffer on sources
-               for name, source in sources.items():
-                       buf = Buffer(source.description)
-                       self.submodules += buf
-                       self.comb += Record.connect(source, buf.d)
-                       setattr(self, name, buf.q)
-
-       def __getattr__(self, name):
-               return getattr(self.decorated, name)
-
-       def __dir__(self):
-               return dir(self.decorated)
diff --git a/lib/sata/frontend/arbiter.py b/lib/sata/frontend/arbiter.py
deleted file mode 100644 (file)
index 678f2d7..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-from lib.sata.common import *
-from lib.sata.frontend.common import *
-
-from migen.genlib.roundrobin import *
-
-class SATAArbiter(Module):
-       def __init__(self, slaves, master):
-               if len(slaves) == 1:
-                       self.comb += slaves[0].connect(master)
-               else:
-                       self.rr = RoundRobin(len(slaves))
-                       self.grant = self.rr.grant
-                       cases = {}
-                       for i, slave in enumerate(slaves):
-                               sink, source = slave.sink, slave.source
-                               start = Signal()
-                               done = Signal()
-                               ongoing = Signal()
-                               self.comb += [
-                                       start.eq(sink.stb & sink.sop),
-                                       done.eq(source.stb & source.last & source.eop & source.ack)
-                               ]
-                               self.sync += \
-                                       If(start,
-                                               ongoing.eq(1)
-                                       ).Elif(done,
-                                               ongoing.eq(0)
-                                       )
-                               self.comb += self.rr.request[i].eq((start | ongoing) & ~done)
-                               cases[i] = [slaves[i].connect(master)]
-                       self.comb += Case(self.grant, cases)
diff --git a/lib/sata/frontend/common.py b/lib/sata/frontend/common.py
deleted file mode 100644 (file)
index 114a0a8..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-from lib.sata.common import *
-
-class SATAMasterPort:
-       def __init__(self, dw):
-               self.source = Source(command_tx_description(dw))
-               self.sink = Sink(command_rx_description(dw))
-
-       def connect(self, slave):
-               return [
-                       Record.connect(self.source, slave.sink),
-                       Record.connect(slave.source, self.sink)
-               ]
-
-class SATASlavePort:
-       def __init__(self, dw):
-               self.sink = Sink(command_tx_description(dw))
-               self.source = Source(command_rx_description(dw))
-
-       def connect(self, master):
-               return [
-                       Record.connect(self.sink, master.source),
-                       Record.connect(master.sink, self.source)
-               ]
diff --git a/lib/sata/frontend/crossbar.py b/lib/sata/frontend/crossbar.py
deleted file mode 100644 (file)
index 41ac806..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-from lib.sata.common import *
-from lib.sata.frontend.common import *
-from lib.sata.frontend.arbiter import SATAArbiter
-
-class SATACrossbar(Module):
-       def __init__(self, dw):
-               self.dw = dw
-               self.slaves = []
-               self.master = SATAMasterPort(dw)
-
-       def get_port(self):
-               master = SATAMasterPort(self.dw)
-               slave = SATASlavePort(self.dw)
-               self.comb += master.connect(slave)
-               self.slaves.append(slave)
-               return master
-
-       def get_ports(self, n):
-               masters = []
-               for i in range(n):
-                       masters.append(self.get_port())
-               return masters
-
-       def do_finalize(self):
-               self.arbiter = SATAArbiter(self.slaves, self.master)
diff --git a/lib/sata/link/__init__.py b/lib/sata/link/__init__.py
deleted file mode 100644 (file)
index b142e68..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-from lib.sata.common import *
-from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
-from lib.sata.link.scrambler import SATAScrambler
-from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
-
-from_rx = [
-       ("idle", 1),
-       ("insert", 32),
-       ("det", 32)
-]
-
-class SATALinkTX(Module):
-       def __init__(self, phy):
-               self.sink = Sink(link_description(32))
-               self.from_rx = Sink(from_rx)
-
-               ###
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-
-               # insert CRC
-               crc = SATACRCInserter(link_description(32))
-               self.submodules += crc
-
-               # scramble
-               scrambler = SATAScrambler(link_description(32))
-               self.submodules += scrambler
-
-               # connect CRC / scrambler
-               self.comb += [
-                       Record.connect(self.sink, crc.sink),
-                       Record.connect(crc.source, scrambler.sink)
-               ]
-
-               # inserter CONT and scrambled data between
-               # CONT and next primitive
-               self.cont  = cont = BufferizeEndpoints(SATACONTInserter(phy_description(32)), "source")
-
-               # datas / primitives mux
-               insert = Signal(32)
-               self.comb += [
-                       If(self.from_rx.insert,
-                               cont.sink.stb.eq(1),
-                               cont.sink.data.eq(self.from_rx.insert),
-                               cont.sink.charisk.eq(0x0001),
-                       ).
-                       Elif(insert,
-                               cont.sink.stb.eq(1),
-                               cont.sink.data.eq(insert),
-                               cont.sink.charisk.eq(0x0001),
-                       ).Elif(fsm.ongoing("COPY"),
-                               cont.sink.stb.eq(scrambler.source.stb),
-                               cont.sink.data.eq(scrambler.source.d),
-                               scrambler.source.ack.eq(cont.sink.ack),
-                               cont.sink.charisk.eq(0)
-                       )
-               ]
-               self.comb += Record.connect(cont.source, phy.sink)
-
-               # FSM
-               fsm.act("IDLE",
-                       scrambler.reset.eq(1),
-                       If(self.from_rx.idle,
-                               insert.eq(primitives["SYNC"]),
-                               If(scrambler.source.stb & scrambler.source.sop,
-                                       If(self.from_rx.det == primitives["SYNC"],
-                                               NextState("RDY")
-                                       )
-                               )
-                       )
-               )
-               fsm.act("RDY",
-                       insert.eq(primitives["X_RDY"]),
-                       If(~self.from_rx.idle,
-                               NextState("IDLE")
-                       ).Elif(self.from_rx.det == primitives["R_RDY"],
-                               NextState("SOF")
-                       )
-               )
-               fsm.act("SOF",
-                       insert.eq(primitives["SOF"]),
-                       If(phy.sink.ack,
-                               NextState("COPY")
-                       )
-               )
-               fsm.act("COPY",
-                       If(self.from_rx.det == primitives["HOLD"],
-                               insert.eq(primitives["HOLDA"]),
-                       ).Elif(~scrambler.source.stb,
-                               insert.eq(primitives["HOLD"]),
-                       ).Elif(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
-                               NextState("EOF")
-                       )
-               )
-               fsm.act("EOF",
-                       insert.eq(primitives["EOF"]),
-                       If(phy.sink.ack,
-                               NextState("WTRM")
-                       )
-               )
-               fsm.act("WTRM",
-                       insert.eq(primitives["WTRM"]),
-                       If(self.from_rx.det == primitives["R_OK"],
-                               NextState("IDLE")
-                       ).Elif(self.from_rx.det == primitives["R_ERR"],
-                               NextState("IDLE")
-                       )
-               )
-
-class SATALinkRX(Module):
-       def __init__(self, phy):
-               self.source = Source(link_description(32))
-               self.to_tx = Source(from_rx)
-
-               ###
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-
-               # CONT remover
-               self.cont = cont = BufferizeEndpoints(SATACONTRemover(phy_description(32)), "source")
-               self.comb += Record.connect(phy.source, cont.sink)
-
-               # datas / primitives detection
-               insert = Signal(32)
-               det = Signal(32)
-               self.comb += \
-                       If(cont.source.stb & (cont.source.charisk == 0b0001),
-                               det.eq(cont.source.data)
-                       )
-
-               # descrambler
-               self.scrambler = scrambler = SATAScrambler(link_description(32))
-
-               # check CRC
-               self.crc = crc = SATACRCChecker(link_description(32))
-
-               sop = Signal()
-               eop = Signal()
-               self.sync += \
-                       If(fsm.ongoing("IDLE"),
-                               sop.eq(1),
-                       ).Elif(fsm.ongoing("COPY"),
-                               If(scrambler.sink.stb & scrambler.sink.ack,
-                                       sop.eq(0)
-                               )
-                       )
-               self.comb += eop.eq(det == primitives["EOF"])
-
-               crc_error = Signal()
-               self.sync += \
-                       If(crc.source.stb & crc.source.eop & crc.source.ack,
-                               crc_error.eq(crc.source.error)
-                       )
-
-               # small fifo to manage HOLD
-               self.fifo = SyncFIFO(link_description(32), 32)
-
-               # graph
-               self.comb += [
-                       cont.source.ack.eq(1),
-                       Record.connect(scrambler.source, crc.sink),
-                       Record.connect(crc.source, self.fifo.sink),
-                       Record.connect(self.fifo.source, self.source)
-               ]
-               cont_source_data_d = Signal(32)
-               self.sync += \
-                       If(cont.source.stb & (det == 0),
-                               scrambler.sink.d.eq(cont.source.data)
-                       )
-
-               # FSM
-               fsm.act("IDLE",
-                       scrambler.reset.eq(1),
-                       If(det == primitives["X_RDY"],
-                               NextState("RDY")
-                       )
-               )
-               fsm.act("RDY",
-                       insert.eq(primitives["R_RDY"]),
-                       If(det == primitives["SOF"],
-                               NextState("WAIT_FIRST")
-                       )
-               )
-               fsm.act("WAIT_FIRST",
-                       insert.eq(primitives["R_IP"]),
-                       If(cont.source.stb & (det == 0),
-                               NextState("COPY")
-                       )
-               )
-               self.comb += [
-                       scrambler.sink.sop.eq(sop),
-                       scrambler.sink.eop.eq(eop)
-               ]
-               fsm.act("COPY",
-                       scrambler.sink.stb.eq(cont.source.stb & ((det == 0) | eop)),
-                       insert.eq(primitives["R_IP"]),
-                       If(det == primitives["HOLD"],
-                               insert.eq(primitives["HOLDA"])
-                       ).Elif(det == primitives["EOF"],
-                               NextState("WTRM")
-                       ).Elif(self.fifo.fifo.level > 8,
-                               insert.eq(primitives["HOLD"])
-                       )
-               )
-               fsm.act("EOF",
-                       insert.eq(primitives["R_IP"]),
-                       If(det == primitives["WTRM"],
-                               NextState("WTRM")
-                       )
-               )
-               fsm.act("WTRM",
-                       insert.eq(primitives["R_IP"]),
-                       If(~crc_error,
-                               NextState("R_OK")
-                       ).Else(
-                               NextState("R_ERR")
-                       )
-               )
-               fsm.act("R_OK",
-                       insert.eq(primitives["R_OK"]),
-                       If(det == primitives["SYNC"],
-                               NextState("IDLE")
-                       )
-               )
-               fsm.act("R_ERR",
-                       insert.eq(primitives["R_ERR"]),
-                       If(det == primitives["SYNC"],
-                               NextState("IDLE")
-                       )
-               )
-
-               # to TX
-               self.comb += [
-                       self.to_tx.idle.eq(fsm.ongoing("IDLE")),
-                       self.to_tx.insert.eq(insert),
-                       self.to_tx.det.eq(det)
-               ]
-
-class SATALink(Module):
-       def __init__(self, phy):
-               self.tx = SATALinkTX(phy)
-               self.rx = SATALinkRX(phy)
-               self.comb += Record.connect(self.rx.to_tx, self.tx.from_rx)
-               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/lib/sata/link/cont.py b/lib/sata/link/cont.py
deleted file mode 100644 (file)
index ece5896..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-from lib.sata.common import *
-from lib.sata.link.scrambler import Scrambler
-
-from migen.genlib.misc import optree
-
-class SATACONTInserter(Module):
-       def __init__(self, description):
-               self.sink = sink = Sink(description)
-               self.source = source = Source(description)
-
-               ###
-
-               self.counter = counter = Counter(max=4)
-
-               is_data = Signal()
-               was_data = Signal()
-               was_hold = Signal()
-               change = Signal()
-               self.comb += is_data.eq(sink.charisk == 0)
-
-               last_data = Signal(32)
-               last_primitive = Signal(32)
-               last_charisk = Signal(4)
-               self.sync += [
-                       If(sink.stb & source.ack,
-                               last_data.eq(sink.data),
-                               last_charisk.eq(sink.charisk),
-                               If(~is_data,
-                                       last_primitive.eq(sink.data),
-                               ),
-                               was_data.eq(is_data),
-                               was_hold.eq(last_primitive == primitives["HOLD"])
-                       )
-               ]
-               self.comb += change.eq(
-                       (sink.data != last_data) |
-                       (sink.charisk != last_charisk) |
-                       is_data
-               )
-
-               # scrambler
-               self.scrambler = scrambler = InsertReset(Scrambler())
-
-               # Datapath
-               self.comb += [
-                       Record.connect(sink, source),
-                       If(sink.stb,
-                               If(~change,
-                                       counter.ce.eq(sink.ack & (counter.value !=2)),
-                                       # insert CONT
-                                       If(counter.value == 1,
-                                               source.charisk.eq(0b0001),
-                                               source.data.eq(primitives["CONT"])
-                                       # insert scrambled data for EMI
-                                       ).Elif(counter.value == 2,
-                                               scrambler.ce.eq(sink.ack),
-                                               source.charisk.eq(0b0000),
-                                               source.data.eq(scrambler.value)
-                                       )
-                               ).Else(
-                                       counter.reset.eq(source.ack),
-                                       If(counter.value == 2,
-                                               # Reinsert last primitive
-                                               If(is_data | (~is_data & was_hold),
-                                                       source.stb.eq(1),
-                                                       sink.ack.eq(0),
-                                                       source.charisk.eq(0b0001),
-                                                       source.data.eq(last_primitive)
-                                               )
-                                       )
-                               )
-                       )
-               ]
-
-class SATACONTRemover(Module):
-       def __init__(self, description):
-               self.sink = sink = Sink(description)
-               self.source = source = Source(description)
-
-               ###
-
-               is_data = Signal()
-               is_cont = Signal()
-               in_cont = Signal()
-               cont_ongoing = Signal()
-
-               self.comb += [
-                       is_data.eq(sink.charisk == 0),
-                       is_cont.eq(~is_data & (sink.data == primitives["CONT"]))
-               ]
-               self.sync += \
-                       If(sink.stb & sink.ack,
-                               If(is_cont,
-                                       in_cont.eq(1)
-                               ).Elif(~is_data,
-                                       in_cont.eq(0)
-                               )
-                       )
-               self.comb += cont_ongoing.eq(is_cont | (in_cont & is_data))
-
-               # Datapath
-               last_primitive = Signal(32)
-               self.sync += [
-                       If(sink.stb & sink.ack,
-                               If(~is_data & ~is_cont,
-                                       last_primitive.eq(sink.data)
-                               )
-                       )
-               ]
-               self.comb += [
-                       Record.connect(sink, source),
-                       If(cont_ongoing,
-                               source.charisk.eq(0b0001),
-                               source.data.eq(last_primitive)
-                       )
-               ]
diff --git a/lib/sata/link/crc.py b/lib/sata/link/crc.py
deleted file mode 100644 (file)
index 4d6c67b..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-from lib.sata.common import *
-
-from migen.genlib.misc import optree
-from migen.actorlib.crc import CRCInserter, CRCChecker
-
-class CRCEngine(Module):
-       """Cyclic Redundancy Check Engine
-
-       Compute next CRC value from last CRC value and data input using
-       an optimized asynchronous LFSR.
-
-       Parameters
-       ----------
-       width : int
-               Width of the data bus and CRC.
-       polynom : int
-               Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
-
-       Attributes
-       ----------
-       d : in
-               Data input.
-       last : in
-               last CRC value.
-       next :
-               next CRC value.
-       """
-       def __init__(self, width, polynom):
-               self.d = Signal(width)
-               self.last = Signal(width)
-               self.next = Signal(width)
-
-               ###
-
-               def _optimize_eq(l):
-                       """
-                       Replace even numbers of XORs in the equation
-                       with an equivalent XOR
-                       """
-                       d = {}
-                       for e in l:
-                               if e in d:
-                                       d[e] += 1
-                               else:
-                                       d[e] = 1
-                       r = []
-                       for key, value in d.items():
-                               if value%2 != 0:
-                                       r.append(key)
-                       return r
-
-               new = Signal(32)
-               self.comb += new.eq(self.last ^ self.d)
-
-               # compute and optimize CRC's LFSR
-               curval = [[("new", i)] for i in range(width)]
-               for i in range(width):
-                       feedback = curval.pop()
-                       for j in range(width-1):
-                               if (polynom & (1<<(j+1))):
-                                       curval[j] += feedback
-                               curval[j] = _optimize_eq(curval[j])
-                       curval.insert(0, feedback)
-
-               # implement logic
-               for i in range(width):
-                       xors = []
-                       for t, n in curval[i]:
-                               if t == "new":
-                                       xors += [new[n]]
-                       self.comb += self.next[i].eq(optree("^", xors))
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class SATACRC(Module):
-       """SATA CRC
-
-       Implement a SATA CRC generator/checker
-
-       Attributes
-       ----------
-       value : out
-               CRC value (used for generator).
-       error : out
-               CRC error (used for checker).
-       """
-       width = 32
-       polynom = 0x04C11DB7
-       init = 0x52325032
-       check = 0x00000000
-       def __init__(self, dw=32):
-               self.d = Signal(self.width)
-               self.value = Signal(self.width)
-               self.error = Signal()
-
-               ###
-
-               self.engine = CRCEngine(self.width, self.polynom)
-               reg_i = Signal(self.width, reset=self.init)
-               self.sync += reg_i.eq(self.engine.next)
-               self.comb += [
-                       self.engine.d.eq(self.d),
-                       self.engine.last.eq(reg_i),
-
-                       self.value.eq(reg_i),
-                       self.error.eq(self.engine.next != self.check)
-               ]
-
-class SATACRCInserter(CRCInserter):
-       def __init__(self, description):
-               CRCInserter.__init__(self, SATACRC, description)
-
-class SATACRCChecker(CRCChecker):
-       def __init__(self, description):
-               CRCChecker.__init__(self, SATACRC, description)
diff --git a/lib/sata/link/scrambler.py b/lib/sata/link/scrambler.py
deleted file mode 100644 (file)
index d2b473f..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-from lib.sata.common import *
-
-from migen.fhdl.std import *
-from migen.genlib.misc import optree
-
-@DecorateModule(InsertCE)
-class Scrambler(Module):
-       """SATA Scrambler
-
-       Implement a SATA Scrambler
-
-       Attributes
-       ----------
-       value : out
-               Scrambled value.
-       """
-       def __init__(self):
-               self.value = Signal(32)
-
-               ###
-
-               context = Signal(16, reset=0xf0f6)
-               next_value = Signal(32)
-               self.sync += context.eq(next_value[16:32])
-
-               # XXX: from SATA specification, replace it with
-               # a generic implementation using polynoms.
-               lfsr_coefs = (
-                       (15, 13, 4, 0), #0
-                       (15, 14, 13, 5, 4, 1, 0),
-                       (14, 13, 6, 5, 4, 2,1, 0),
-                       (15, 14, 7, 6, 5, 3,2, 1),
-                       (13, 8, 7, 6, 3, 2, 0),
-                       (14, 9, 8, 7, 4, 3, 1),
-                       (15, 10, 9, 8, 5, 4, 2),
-                       (15, 13, 11, 10, 9, 6, 5, 4, 3, 0),
-                       (15, 14, 13, 12, 11, 10,7, 6, 5, 1, 0),
-                       (14, 12, 11, 8, 7, 6, 4, 2, 1, 0),
-                       (15, 13, 12, 9, 8, 7, 5, 3, 2, 1),
-                       (15, 14, 10, 9, 8, 6, 3, 2, 0),
-                       (13, 11, 10, 9, 7, 3, 1, 0),
-                       (14, 12, 11, 10, 8, 4, 2, 1),
-                       (15, 13, 12, 11, 9, 5, 3, 2),
-                       (15, 14, 12, 10, 6, 3, 0),
-
-                       (11, 7, 1, 0), #16
-                       (12, 8, 2, 1),
-                       (13, 9, 3, 2),
-                       (14, 10, 4, 3),
-                       (15, 11, 5, 4),
-                       (15, 13, 12, 6, 5, 4, 0),
-                       (15, 14, 7, 6, 5, 4, 1, 0),
-                       (13, 8, 7, 6, 5, 4, 2, 1, 0),
-                       (14, 9, 8,7, 6, 5, 3, 2, 1),
-                       (15, 10, 9, 8, 7, 6, 4, 3, 2),
-                       (15, 13, 11, 10, 9, 8, 7, 5, 3, 0),
-                       (15, 14, 13, 12, 11, 10, 9, 8, 6, 1, 0),
-                       (14, 12, 11, 10, 9, 7, 4, 2, 1, 0),
-                       (15, 13, 12, 11, 10, 8, 5, 3, 2, 1),
-                       (15, 14, 12, 11, 9, 6, 3, 2, 0),
-                       (12, 10, 7, 3, 1, 0),
-               )
-
-               for n, coefs in enumerate(lfsr_coefs):
-                       eq = [context[i] for i in coefs]
-                       self.comb += next_value[n].eq(optree("^", eq))
-
-               self.comb += self.value.eq(next_value)
-
-@DecorateModule(InsertReset)
-class SATAScrambler(Module):
-       def __init__(self, description):
-               self.sink = sink = Sink(description)
-               self.source = source = Source(description)
-
-               ###
-
-               self.scrambler = Scrambler()
-               self.comb += [
-                       self.scrambler.ce.eq(sink.stb & sink.ack),
-                       Record.connect(sink, source),
-                       source.d.eq(sink.d ^ self.scrambler.value)
-               ]
diff --git a/lib/sata/phy/__init__.py b/lib/sata/phy/__init__.py
deleted file mode 100644 (file)
index 925d772..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-from lib.sata.common import *
-from lib.sata.phy.ctrl import SATAPHYHostCtrl
-from lib.sata.phy.datapath import SATAPHYDatapath
-
-class SATAPHY(Module):
-       def __init__(self, pads, clk_freq, host=True, device_family="k7", speed="SATA1"):
-               self.speed = speed
-       # Transceiver / Clocks
-               if device_family == "k7":
-                       from lib.sata.phy.k7.trx import K7SATAPHYTRX
-                       from lib.sata.phy.k7.crg import K7SATAPHYCRG
-                       self.trx = K7SATAPHYTRX(pads, speed)
-                       self.crg = K7SATAPHYCRG(pads, self.trx, clk_freq, speed)
-               else:
-                       raise NotImplementedError(device_family + "device family not implemented")
-
-       # Control
-               if host:
-                       self.ctrl = SATAPHYHostCtrl(self.trx, self.crg, clk_freq)
-               else:
-                       self.ctrl = SATAPHYDeviceCtrl(self.trx, self.crg, clk_freq)
-
-       # Datapath
-               self.datapath = SATAPHYDatapath(self.trx, self.ctrl)
-               self.sink, self.source = self.datapath.sink, self.datapath.source
diff --git a/lib/sata/phy/ctrl.py b/lib/sata/phy/ctrl.py
deleted file mode 100644 (file)
index c574d7e..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-from math import ceil
-
-from lib.sata.common import *
-
-def us(t, clk_freq):
-       clk_period_us = 1000000/clk_freq
-       return ceil(t/clk_period_us)
-
-class SATAPHYHostCtrlTimeout(Module):
-       def __init__(self, load):
-               self.load = Signal()
-               self.dec = Signal()
-               self.reached = Signal()
-
-               cnt = Signal(max=load+1)
-               self.sync += \
-                       If(self.load,
-                               cnt.eq(load)
-                       ).Elif(self.dec & ~self.reached,
-                               cnt.eq(cnt-1)
-                       )
-               self.comb += self.reached.eq(cnt == 0)
-
-class SATAPHYHostCtrl(Module):
-       def __init__(self, trx, crg, clk_freq):
-               self.ready = Signal()
-               self.need_reset = Signal()
-               self.sink = sink = Sink(phy_description(32))
-               self.source = source = Source(phy_description(32))
-
-               ###
-               self.comb += [
-                       source.stb.eq(1),
-                       sink.ack.eq(1)
-               ]
-
-               retry_timeout = SATAPHYHostCtrlTimeout(us(10000, clk_freq))
-               align_timeout = SATAPHYHostCtrlTimeout(us(873, clk_freq))
-               self.submodules += align_timeout, retry_timeout
-
-               align_detect = Signal()
-               non_align_cnt = Signal(4)
-
-               self.fsm = fsm = FSM(reset_state="RESET")
-               fsm.act("RESET",
-                       trx.tx_idle.eq(1),
-                       retry_timeout.load.eq(1),
-                       align_timeout.load.eq(1),
-                       If(crg.ready,
-                               NextState("COMINIT")
-                       ),
-               )
-               fsm.act("COMINIT",
-                       trx.tx_idle.eq(1),
-                       trx.tx_cominit_stb.eq(1),
-                       If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
-                               NextState("AWAIT_COMINIT")
-                       ),
-               )
-               fsm.act("AWAIT_COMINIT",
-                       trx.tx_idle.eq(1),
-                       retry_timeout.dec.eq(1),
-                       If(trx.rx_cominit_stb,
-                               NextState("AWAIT_NO_COMINIT")
-                       ).Else(
-                               If(retry_timeout.reached,
-                                       NextState("RESET")
-                               )
-                       ),
-               )
-               fsm.act("AWAIT_NO_COMINIT",
-                       trx.tx_idle.eq(1),
-                       retry_timeout.load.eq(1),
-                       If(~trx.rx_cominit_stb,
-                               NextState("CALIBRATE")
-                       ),
-               )
-               fsm.act("CALIBRATE",
-                       trx.tx_idle.eq(1),
-                       NextState("COMWAKE"),
-               )
-               fsm.act("COMWAKE",
-                       trx.tx_idle.eq(1),
-                       trx.tx_comwake_stb.eq(1),
-                       If(trx.tx_comwake_ack,
-                               NextState("AWAIT_COMWAKE")
-                       ),
-               )
-               fsm.act("AWAIT_COMWAKE",
-                       trx.tx_idle.eq(1),
-                       retry_timeout.dec.eq(1),
-                       If(trx.rx_comwake_stb,
-                               NextState("AWAIT_NO_COMWAKE")
-                       ).Else(
-                               If(retry_timeout.reached,
-                                       NextState("RESET")
-                               )
-                       ),
-               )
-               fsm.act("AWAIT_NO_COMWAKE",
-                       trx.tx_idle.eq(1),
-                       If(~trx.rx_comwake_stb,
-                               NextState("AWAIT_NO_RX_IDLE")
-                       ),
-               )
-               fsm.act("AWAIT_NO_RX_IDLE",
-                       trx.tx_idle.eq(0),
-                       source.data.eq(0x4A4A4A4A), #D10.2
-                       source.charisk.eq(0b0000),
-                       If(~trx.rx_idle,
-                               NextState("AWAIT_ALIGN"),
-                               crg.reset.eq(1),
-                               trx.pmarxreset.eq(1)
-                       ),
-               )
-               fsm.act("AWAIT_ALIGN",
-                       trx.tx_idle.eq(0),
-                       source.data.eq(0x4A4A4A4A), #D10.2
-                       source.charisk.eq(0b0000),
-                       trx.rx_align.eq(1),
-                       align_timeout.dec.eq(1),
-                       If(align_detect & ~trx.rx_idle,
-                               NextState("SEND_ALIGN")
-                       ).Elif(align_timeout.reached,
-                               NextState("RESET")
-                       ),
-               )
-               fsm.act("SEND_ALIGN",
-                       trx.tx_idle.eq(0),
-                       trx.rx_align.eq(1),
-                       source.data.eq(primitives["ALIGN"]),
-                       source.charisk.eq(0b0001),
-                       If(non_align_cnt == 3,
-                               NextState("READY")
-                       ),
-               )
-               fsm.act("READY",
-                       trx.tx_idle.eq(0),
-                       trx.rx_align.eq(1),
-                       source.data.eq(primitives["SYNC"]),
-                       source.charisk.eq(0b0001),
-                       If(trx.rx_idle,
-                               NextState("RESET")
-                       ),
-                       self.ready.eq(1),
-               )
-
-               self.reset_timeout = Timeout(clk_freq//16)
-               self.comb += [
-                       self.reset_timeout.ce.eq(~self.ready),
-                       self.need_reset.eq(self.reset_timeout.reached)
-               ]
-
-               self.comb +=  \
-                       align_detect.eq(self.sink.stb & (self.sink.data == primitives["ALIGN"]))
-               self.sync += \
-                       If(fsm.ongoing("SEND_ALIGN"),
-                               If(sink.stb,
-                                       If(sink.data[0:8] == 0x7C,
-                                               non_align_cnt.eq(non_align_cnt + 1)
-                                       ).Else(
-                                               non_align_cnt.eq(0)
-                                       )
-                               )
-                       )
diff --git a/lib/sata/phy/datapath.py b/lib/sata/phy/datapath.py
deleted file mode 100644 (file)
index 8930955..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-from lib.sata.common import *
-
-from migen.genlib.misc import chooser
-from migen.flow.plumbing import Multiplexer, Demultiplexer
-from migen.actorlib.structuring import Converter
-
-class SATAPHYDatapathRX(Module):
-       def __init__(self):
-               self.sink = Sink(phy_description(16))
-               self.source = Source(phy_description(32))
-
-               ###
-
-       # width convertion (16 to 32) and byte alignment
-               byte_alignment = Signal()
-               last_charisk = Signal(2)
-               last_data = Signal(16)
-               self.sync.sata_rx += \
-                       If(self.sink.stb & self.sink.ack,
-                               If(self.sink.charisk != 0,
-                                       byte_alignment.eq(self.sink.charisk[1])
-                               ),
-                               last_charisk.eq(self.sink.charisk),
-                               last_data.eq(self.sink.data)
-                       )
-               converter = Converter(phy_description(16), phy_description(32), reverse=False)
-               self.converter = InsertReset(RenameClockDomains(converter, "sata_rx"))
-               self.comb += [
-                       self.converter.sink.stb.eq(self.sink.stb),
-                       If(byte_alignment,
-                               self.converter.sink.charisk.eq(Cat(last_charisk[1], self.sink.charisk[0])),
-                               self.converter.sink.data.eq(Cat(last_data[8:], self.sink.data[:8]))
-                       ).Else(
-                               self.converter.sink.charisk.eq(self.sink.charisk),
-                               self.converter.sink.data.eq(self.sink.data)
-                       ),
-                       self.sink.ack.eq(self.converter.sink.ack),
-                       self.converter.reset.eq(self.converter.source.charisk[2:] != 0)
-               ]
-
-       # clock domain crossing
-               # (SATA3) 300MHz sata_rx clk to sys_clk
-               # (SATA2) 150MHz sata_rx clk to sys_clk
-               # (SATA1) 75MHz sata_rx clk to sys_clk
-               # requirements:
-               # due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
-               # source destination is always able to accept data (ack always 1)
-               fifo = AsyncFIFO(phy_description(32), 4)
-               self.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
-               self.comb += [
-                       Record.connect(self.converter.source, fifo.sink),
-                       Record.connect(fifo.source, self.source)
-               ]
-
-class SATAPHYDatapathTX(Module):
-       def __init__(self):
-               self.sink = Sink(phy_description(32))
-               self.source = Source(phy_description(16))
-
-               ###
-
-       # clock domain crossing
-               # (SATA3) sys_clk to 300MHz sata_tx clk
-               # (SATA2) sys_clk to 150MHz sata_tx clk
-               # (SATA1) sys_clk to 75MHz sata_tx clk
-               # requirements:
-               # source destination is always able to accept data (ack always 1)
-               fifo = AsyncFIFO(phy_description(32), 4)
-               self.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
-               self.comb += Record.connect(self.sink, fifo.sink)
-
-       # width convertion (32 to 16)
-               converter = Converter(phy_description(32), phy_description(16), reverse=False)
-               self.converter =  RenameClockDomains(converter, "sata_tx")
-               self.comb += [
-                       Record.connect(self.fifo.source, self.converter.sink),
-                       Record.connect(self.converter.source, self.source)
-               ]
-
-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))
-               self.source = Source(phy_description(32))
-
-               ###
-
-       # TX path
-               self.align_inserter = SATAPHYAlignInserter(ctrl)
-               self.mux = Multiplexer(phy_description(32), 2)
-               self.tx = SATAPHYDatapathTX()
-               self.comb += [
-                       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)
-               ]
-
-       # RX path
-               self.rx = SATAPHYDatapathRX()
-               self.demux = Demultiplexer(phy_description(32), 2)
-               self.align_remover = SATAPHYAlignRemover()
-               self.comb += [
-                       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)
-               ]
diff --git a/lib/sata/phy/k7/crg.py b/lib/sata/phy/k7/crg.py
deleted file mode 100644 (file)
index 7e57e60..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-from math import ceil
-
-from lib.sata.common import *
-
-class K7SATAPHYCRG(Module):
-       def __init__(self, pads, gtx, clk_freq, speed):
-               self.reset = Signal()
-               self.ready = Signal()
-
-               self.cd_sata_tx = ClockDomain()
-               self.cd_sata_rx = ClockDomain()
-
-       # CPLL
-               # (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
-               # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output dividers.
-               refclk = Signal()
-               self.specials += Instance("IBUFDS_GTE2",
-                       i_CEB=0,
-                       i_I=pads.refclk_p,
-                       i_IB=pads.refclk_n,
-                       o_O=refclk
-               )
-               self.comb += gtx.gtrefclk0.eq(refclk)
-
-       # TX clocking
-               # (SATA3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits)
-               # (SATA2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits)
-               # (SATA1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits)
-               mmcm_reset = Signal()
-               mmcm_locked = Signal()
-               mmcm_fb = Signal()
-               mmcm_clk_i = Signal()
-               mmcm_clk0_o = Signal()
-               mmcm_div_config = {
-                       "SATA1" :       16.0,
-                       "SATA2" :       8.0,
-                       "SATA3" :       4.0
-                       }
-               mmcm_div = mmcm_div_config[speed]
-               self.specials += [
-                       Instance("BUFG", i_I=gtx.txoutclk, o_O=mmcm_clk_i),
-                       Instance("MMCME2_ADV",
-                               p_BANDWIDTH="HIGH", p_COMPENSATION="ZHOLD", i_RST=mmcm_reset, o_LOCKED=mmcm_locked,
-
-                               # DRP
-                               i_DCLK=0, i_DEN=0, i_DWE=0, #o_DRDY=,
-                               i_DADDR=0, i_DI=0, #o_DO=,
-
-                               # VCO
-                               p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.666,
-                               p_CLKFBOUT_MULT_F=8.000, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1,
-                               i_CLKIN1=mmcm_clk_i, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb,
-
-                               # CLK0
-                               p_CLKOUT0_DIVIDE_F=mmcm_div, p_CLKOUT0_PHASE=0.000, o_CLKOUT0=mmcm_clk0_o,
-                       ),
-                       Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk),
-               ]
-               self.comb += [
-                       gtx.txusrclk.eq(self.cd_sata_tx.clk),
-                       gtx.txusrclk2.eq(self.cd_sata_tx.clk)
-               ]
-
-       # RX clocking
-               # (SATA3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK
-               # (SATA2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
-               # (SATA1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
-               self.specials += [
-                       Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
-               ]
-               self.comb += [
-                       gtx.rxusrclk.eq(self.cd_sata_rx.clk),
-                       gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
-               ]
-
-       # Configuration Reset
-               # After configuration, GTX's resets have to stay low for at least 500ns
-               # See AR43482
-               reset_en = Signal()
-               clk_period_ns = 1000000000/clk_freq
-               reset_en_cnt_max = ceil(500/clk_period_ns)
-               reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1)
-               self.sync += \
-                       If(self.reset,
-                               reset_en_cnt.eq(reset_en_cnt.reset)
-                       ).Elif(~reset_en,
-                               reset_en_cnt.eq(reset_en_cnt-1)
-                       )
-               self.comb += reset_en.eq(reset_en_cnt == 0)
-
-       # TX Reset FSM
-               tx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
-               self.submodules += tx_reset_fsm
-               self.comb += tx_reset_fsm.reset.eq(self.reset)
-               tx_reset_fsm.act("IDLE",
-                       If(reset_en,
-                               NextState("RESET_GTX"),
-                       )
-               )
-               tx_reset_fsm.act("RESET_GTX",
-                       gtx.gttxreset.eq(1),
-                       If(gtx.cplllock & mmcm_locked,
-                               NextState("RELEASE_GTX")
-                       )
-               )
-               tx_reset_fsm.act("RELEASE_GTX",
-                       gtx.txuserrdy.eq(1),
-                       If(gtx.txresetdone,
-                               NextState("READY")
-                       )
-               )
-               tx_reset_fsm.act("READY",
-                       gtx.txuserrdy.eq(1)
-               )
-
-       # RX Reset FSM
-               rx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
-               self.submodules += rx_reset_fsm
-               self.comb += rx_reset_fsm.reset.eq(self.reset)
-
-               rx_reset_fsm.act("IDLE",
-                       If(reset_en,
-                               NextState("RESET_GTX"),
-                       )
-               )
-               rx_reset_fsm.act("RESET_GTX",
-                       gtx.gtrxreset.eq(1),
-                       If(gtx.cplllock & mmcm_locked,
-                               NextState("RELEASE_GTX")
-                       )
-               )
-               rx_reset_fsm.act("RELEASE_GTX",
-                       gtx.rxuserrdy.eq(1),
-                       If(gtx.rxresetdone,
-                               NextState("READY")
-                       )
-               )
-               rx_reset_fsm.act("READY",
-                       gtx.rxuserrdy.eq(1)
-               )
-
-       # Ready
-               self.tx_ready = tx_reset_fsm.ongoing("READY")
-               self.rx_ready = rx_reset_fsm.ongoing("READY")
-               self.comb += self.ready.eq(self.tx_ready & self.rx_ready)
-
-       # Reset PLL
-               self.comb += gtx.cpllreset.eq(ResetSignal() | self.reset | ~reset_en)
-
-       # Reset MMCM
-               self.comb += mmcm_reset.eq(ResetSignal() | self.reset | ~gtx.cplllock)
-
-       # Reset for SATA TX/RX clock domains
-               self.specials += [
-                       AsyncResetSynchronizer(self.cd_sata_tx, ~self.tx_ready),
-                       AsyncResetSynchronizer(self.cd_sata_rx, ~self.rx_ready),
-               ]
diff --git a/lib/sata/phy/k7/trx.py b/lib/sata/phy/k7/trx.py
deleted file mode 100644 (file)
index eba35f1..0000000
+++ /dev/null
@@ -1,854 +0,0 @@
-from lib.sata.common import *
-
-from migen.genlib.cdc import *
-
-def ones(width):
-       return 2**width-1
-
-class _PulseSynchronizer(PulseSynchronizer):
-       def __init__(self, i, idomain, o, odomain):
-               PulseSynchronizer.__init__(self, idomain, odomain)
-               self.comb += [
-                       self.i.eq(i),
-                       o.eq(self.o)
-               ]
-
-class _RisingEdge(Module):
-       def __init__(self, i, o):
-               i_d = Signal()
-               self.sync += i_d.eq(i)
-               self.comb += o.eq(i & ~i_d)
-
-class K7SATAPHYTRX(Module):
-       def __init__(self, pads, speed):
-       # Common signals
-
-               # control
-               self.tx_idle = Signal()                 #i
-
-               self.tx_cominit_stb = Signal()  #i
-               self.tx_cominit_ack = Signal()  #o
-               self.tx_comwake_stb = Signal()  #i
-               self.tx_comwake_ack = Signal()  #o
-
-               self.rx_idle = Signal()                 #o
-               self.rx_align = Signal()                #i
-
-               self.rx_cominit_stb = Signal()  #o
-               self.rx_comwake_stb = Signal()  #o
-
-               # datapath
-               self.sink = Sink(phy_description(16))
-               self.source = Source(phy_description(16))
-
-       # K7 specific signals
-               # Channel - Ref Clock Ports
-               self.gtrefclk0 = Signal()
-
-               # Channel PLL
-               self.cplllock = Signal()
-               self.cpllreset = Signal()
-
-               # Receive Ports
-               self.rxuserrdy = Signal()
-               self.rxalign = Signal()
-
-               # Receive Ports - 8b10b Decoder
-               self.rxcharisk = Signal(2)
-               self.rxdisperr = Signal(2)
-
-               # Receive Ports - RX Data Path interface
-               self.gtrxreset = Signal()
-               self.pmarxreset = Signal()
-               self.rxdata = Signal(16)
-               self.rxoutclk = Signal()
-               self.rxusrclk = Signal()
-               self.rxusrclk2 = Signal()
-
-               # Receive Ports - RX Driver,OOB signalling,Coupling and Eq.,CDR
-               self.rxelecidle = Signal()
-
-               # Receive Ports - RX PLL Ports
-               self.rxresetdone = Signal()
-
-               # Receive Ports - RX Ports for SATA
-               self.rxcominitdet = Signal()
-               self.rxcomwakedet = Signal()
-
-               # Transmit Ports
-               self.txuserrdy = Signal()
-
-               # Transmit Ports - 8b10b Encoder Control Ports
-               self.txcharisk = Signal(2)
-
-               # Transmit Ports - TX Data Path interface
-               self.gttxreset = Signal()
-               self.txdata = Signal(16)
-               self.txoutclk = Signal()
-               self.txusrclk = Signal()
-               self.txusrclk2 = Signal()
-
-               # Transmit Ports - TX PLL Ports
-               self.txresetdone = Signal()
-
-               # Transmit Ports - TX Ports for PCI Express
-               self.txelecidle = Signal(reset=1)
-
-               # Transmit Ports - TX Ports for SATA
-               self.txcomfinish = Signal()
-               self.txcominit = Signal()
-               self.txcomwake = Signal()
-               self.txrate = Signal(3)
-               self.rxcdrlock = Signal()
-
-       # Config at startup
-               div_config = {
-                       "SATA1" :       4,
-                       "SATA2" :       2,
-                       "SATA3" :       1
-                       }
-               rxout_div = div_config[speed]
-               txout_div = div_config[speed]
-
-               cdr_config = {
-                       "SATA1" :       0x0380008BFF40100008,
-                       "SATA2" :       0x0388008BFF40200008,
-                       "SATA3" :       0X0380008BFF10200010
-               }
-               rxcdr_cfg = cdr_config[speed]
-
-       # Specific / Generic signals encoding/decoding
-               self.comb += [
-                       self.txelecidle.eq(self.tx_idle),
-                       self.tx_cominit_ack.eq(self.tx_cominit_stb & self.txcomfinish),
-                       self.tx_comwake_ack.eq(self.tx_comwake_stb & self.txcomfinish),
-                       self.rx_idle.eq(self.rxelecidle),
-                       self.rxalign.eq(self.rx_align),
-                       self.rx_cominit_stb.eq(self.rxcominitdet),
-                       self.rx_comwake_stb.eq(self.rxcomwakedet),
-               ]
-               self.submodules += [
-                       _RisingEdge(self.tx_cominit_stb, self.txcominit),
-                       _RisingEdge(self.tx_comwake_stb, self.txcomwake),
-               ]
-
-               self.comb += [
-                       self.txcharisk.eq(self.sink.charisk),
-                       self.txdata.eq(self.sink.data),
-                       self.sink.ack.eq(1),
-
-                       self.source.stb.eq(1),
-                       self.source.charisk.eq(self.rxcharisk),
-                       self.source.data.eq(self.rxdata)
-               ]
-
-       # Internals and clock domain crossing
-               # sys_clk --> sata_tx clk
-               txuserrdy = Signal()
-               txelecidle = Signal(reset=1)
-               txcominit = Signal()
-               txcomwake = Signal()
-               txrate = Signal(3)
-
-               self.specials += [
-                       MultiReg(self.txuserrdy, txuserrdy, "sata_tx"),
-                       MultiReg(self.txelecidle, txelecidle, "sata_tx"),
-                       MultiReg(self.txrate, txrate, "sata_tx")
-               ]
-               self.submodules += [
-                       _PulseSynchronizer(self.txcominit, "sys", txcominit, "sata_tx"),
-                       _PulseSynchronizer(self.txcomwake, "sys", txcomwake, "sata_tx"),
-               ]
-
-               # sata_tx clk --> sys clk
-               txresetdone = Signal()
-               txcomfinish = Signal()
-
-               self.specials += [
-                       MultiReg(txresetdone, self.txresetdone, "sys"),
-               ]
-
-               self.submodules += [
-                       _PulseSynchronizer(txcomfinish, "sata_tx", self.txcomfinish, "sys"),
-               ]
-
-               # sys clk --> sata_rx clk
-               rxuserrdy = Signal()
-
-               self.specials += [
-                       MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx"),
-               ]
-
-               # sata_rx clk --> sys clk
-               rxelecidle = Signal()
-               rxelecidle_i = Signal()
-               rxelecidle_cnt_i = Signal(9)
-               rxresetdone = Signal()
-               rxcominitdet = Signal()
-               rxcomwakedet = Signal()
-               rxratedone = Signal()
-               rxcdrlock = Signal()
-
-               self.specials += [
-                       MultiReg(rxelecidle, rxelecidle_i, "sys"),
-                       MultiReg(rxresetdone, self.rxresetdone, "sys"),
-                       MultiReg(rxcominitdet, self.rxcominitdet, "sys"),
-                       MultiReg(rxcomwakedet, self.rxcomwakedet, "sys"),
-                       MultiReg(rxcdrlock, self.rxcdrlock, "sys"),
-               ]
-
-               self.sync += [
-                       If(rxelecidle_i != self.rxelecidle,
-                               If(rxelecidle_cnt_i == 0,
-                                       self.rxelecidle.eq(rxelecidle_i),
-                                       rxelecidle_cnt_i.eq(255)
-                               ).Else(
-                                       rxelecidle_cnt_i.eq(rxelecidle_cnt_i-1)
-                               )
-                       ).Else(
-                               rxelecidle_cnt_i.eq(255)
-                       )
-               ]
-
-               self.rxbyteisaligned = Signal()
-
-       # QPLL input clock
-               self.qpllclk = Signal()
-               self.qpllrefclk = Signal()
-
-       # Instance
-               gtxe2_channel_parameters = {
-                               # Simulation-Only Attributes
-                                       "p_SIM_RECEIVER_DETECT_PASS":"TRUE",
-                                       "p_SIM_TX_EIDLE_DRIVE_LEVEL":"X",
-                                       "p_SIM_RESET_SPEEDUP":"TRUE",
-                                       "p_SIM_CPLLREFCLK_SEL":0b001,
-                                       "p_SIM_VERSION":"4.0",
-
-                               # RX Byte and Word Alignment Attributes
-                                       "p_ALIGN_COMMA_DOUBLE":"FALSE",
-                                       "p_ALIGN_COMMA_ENABLE":ones(10),
-                                       "p_ALIGN_COMMA_WORD":2,
-                                       "p_ALIGN_MCOMMA_DET":"TRUE",
-                                       "p_ALIGN_MCOMMA_VALUE":0b1010000011,
-                                       "p_ALIGN_PCOMMA_DET":"TRUE",
-                                       "p_ALIGN_PCOMMA_VALUE":0b0101111100,
-                                       "p_SHOW_REALIGN_COMMA":"FALSE",
-                                       "p_RXSLIDE_AUTO_WAIT":7,
-                                       "p_RXSLIDE_MODE":"PCS",
-                                       "p_RX_SIG_VALID_DLY":10,
-
-                               # RX 8B/10B Decoder Attributes
-                                       "p_RX_DISPERR_SEQ_MATCH":"TRUE",
-                                       "p_DEC_MCOMMA_DETECT":"TRUE",
-                                       "p_DEC_PCOMMA_DETECT":"TRUE",
-                                       "p_DEC_VALID_COMMA_ONLY":"FALSE",
-
-                               # RX Clock Correction Attributes
-                                       "p_CBCC_DATA_SOURCE_SEL":"DECODED",
-                                       "p_CLK_COR_SEQ_2_USE":"FALSE",
-                                       "p_CLK_COR_KEEP_IDLE":"FALSE",
-                                       "p_CLK_COR_MAX_LAT":9,
-                                       "p_CLK_COR_MIN_LAT":7,
-                                       "p_CLK_COR_PRECEDENCE":"TRUE",
-                                       "p_CLK_COR_REPEAT_WAIT":0,
-                                       "p_CLK_COR_SEQ_LEN":1,
-                                       "p_CLK_COR_SEQ_1_ENABLE":ones(4),
-                                       "p_CLK_COR_SEQ_1_1":0b0100000000,
-                                       "p_CLK_COR_SEQ_1_2":0b0000000000,
-                                       "p_CLK_COR_SEQ_1_3":0b0000000000,
-                                       "p_CLK_COR_SEQ_1_4":0b0000000000,
-                                       "p_CLK_CORRECT_USE":"FALSE",
-                                       "p_CLK_COR_SEQ_2_ENABLE":ones(4),
-                                       "p_CLK_COR_SEQ_2_1":0b0100000000,
-                                       "p_CLK_COR_SEQ_2_2":0,
-                                       "p_CLK_COR_SEQ_2_3":0,
-                                       "p_CLK_COR_SEQ_2_4":0,
-
-                               # RX Channel Bonding Attributes
-                                       "p_CHAN_BOND_KEEP_ALIGN":"FALSE",
-                                       "p_CHAN_BOND_MAX_SKEW":1,
-                                       "p_CHAN_BOND_SEQ_LEN":1,
-                                       "p_CHAN_BOND_SEQ_1_1":0,
-                                       "p_CHAN_BOND_SEQ_1_1":0,
-                                       "p_CHAN_BOND_SEQ_1_2":0,
-                                       "p_CHAN_BOND_SEQ_1_3":0,
-                                       "p_CHAN_BOND_SEQ_1_4":0,
-                                       "p_CHAN_BOND_SEQ_1_ENABLE":ones(4),
-                                       "p_CHAN_BOND_SEQ_2_1":0,
-                                       "p_CHAN_BOND_SEQ_2_2":0,
-                                       "p_CHAN_BOND_SEQ_2_3":0,
-                                       "p_CHAN_BOND_SEQ_2_4":0,
-                                       "p_CHAN_BOND_SEQ_2_ENABLE":ones(4),
-                                       "p_CHAN_BOND_SEQ_2_USE":"FALSE",
-                                       "p_FTS_DESKEW_SEQ_ENABLE":ones(4),
-                                       "p_FTS_LANE_DESKEW_CFG":ones(4),
-                                       "p_FTS_LANE_DESKEW_EN":"FALSE",
-
-                               # RX Margin Analysis Attributes
-                                       "p_ES_CONTROL":0,
-                                       "p_ES_ERRDET_EN":"FALSE",
-                                       "p_ES_EYE_SCAN_EN":"TRUE",
-                                       "p_ES_HORZ_OFFSET":0,
-                                       "p_ES_PMA_CFG":0,
-                                       "p_ES_PRESCALE":0,
-                                       "p_ES_QUALIFIER":0,
-                                       "p_ES_QUAL_MASK":0,
-                                       "p_ES_SDATA_MASK":0,
-                                       "p_ES_VERT_OFFSET":0,
-
-                               # FPGA RX Interface Attributes
-                                       "p_RX_DATA_WIDTH":20,
-
-                               # PMA Attributes
-                                       "p_OUTREFCLK_SEL_INV":0b11,
-                                       "p_PMA_RSV":0x00018480,
-                                       "p_PMA_RSV2":0x2050,
-                                       "p_PMA_RSV3":0,
-                                       "p_PMA_RSV4":0,
-                                       "p_RX_BIAS_CFG":0b100,
-                                       "p_DMONITOR_CFG":0xA00,
-                                       "p_RX_CM_SEL":0b11,
-                                       "p_RX_CM_TRIM":0b010,
-                                       "p_RX_DEBUG_CFG":0,
-                                       "p_RX_OS_CFG":0b10000000,
-                                       "p_TERM_RCAL_CFG":0,
-                                       "p_TERM_RCAL_OVRD":0,
-                                       "p_TST_RSV":0,
-                                       "p_RX_CLK25_DIV":6,
-                                       "p_TX_CLK25_DIV":6,
-                                       "p_UCODEER_CLR":0,
-
-                               # PCI Express Attributes
-                                       "p_PCS_PCIE_EN":"FALSE",
-
-                               # PCS Attributes
-                                       "p_PCS_RSVD_ATTR":0x100,
-
-                               # RX Buffer Attributes
-                                       "p_RXBUF_ADDR_MODE":"FAST",
-                                       "p_RXBUF_EIDLE_HI_CNT":0b1000,
-                                       "p_RXBUF_EIDLE_LO_CNT":0,
-                                       "p_RXBUF_EN":"TRUE",
-                                       "p_RX_BUFFER_CFG":0,
-                                       "p_RXBUF_RESET_ON_CB_CHANGE":"TRUE",
-                                       "p_RXBUF_RESET_ON_COMMAALIGN":"FALSE",
-                                       "p_RXBUF_RESET_ON_EIDLE":"FALSE",
-                                       "p_RXBUF_RESET_ON_RATE_CHANGE":"TRUE",
-                                       "p_RXBUFRESET_TIME":1,
-                                       "p_RXBUF_THRESH_OVFLW":61,
-                                       "p_RXBUF_THRESH_OVRD":"FALSE",
-                                       "p_RXBUF_THRESH_UNDFLW":4,
-                                       "p_RXDLY_CFG":0x1f,
-                                       "p_RXDLY_LCFG":0x30,
-                                       "p_RXDLY_TAP_CFG":0,
-                                       "p_RXPH_CFG":0,
-                                       "p_RXPHDLY_CFG":0x084820,
-                                       "p_RXPH_MONITOR_SEL":0,
-                                       "p_RX_XCLK_SEL":"RXUSR",
-                                       "p_RX_DDI_SEL":0,
-                                       "p_RX_DEFER_RESET_BUF_EN":"TRUE",
-
-                               #CDR Attributes
-                                       "p_RXCDR_CFG":rxcdr_cfg,
-                                       "p_RXCDR_FR_RESET_ON_EIDLE":0,
-                                       "p_RXCDR_HOLD_DURING_EIDLE":0,
-                                       "p_RXCDR_PH_RESET_ON_EIDLE":0,
-                                       "p_RXCDR_LOCK_CFG":0b010101,
-
-                               # RX Initialization and Reset Attributes
-                                       "p_RXCDRFREQRESET_TIME":1,
-                                       "p_RXCDRPHRESET_TIME":1,
-                                       "p_RXISCANRESET_TIME":1,
-                                       "p_RXPCSRESET_TIME":1,
-                                       "p_RXPMARESET_TIME":3,
-
-                               # RX OOB Signaling Attributes
-                                       "p_RXOOB_CFG":0b0000110,
-
-                               # RX Gearbox Attributes
-                                       "p_RXGEARBOX_EN":"FALSE",
-                                       "p_GEARBOX_MODE":0,
-
-                               # PRBS Detection Attribute
-                                       "p_RXPRBS_ERR_LOOPBACK":0,
-
-                               # Power-Down Attributes
-                                       "p_PD_TRANS_TIME_FROM_P2":0x03c,
-                                       "p_PD_TRANS_TIME_NONE_P2":0x3c,
-                                       "p_PD_TRANS_TIME_TO_P2":0x64,
-
-                               # RX OOB Signaling Attributes
-                                       "p_SAS_MAX_COM":64,
-                                       "p_SAS_MIN_COM":36,
-                                       "p_SATA_BURST_SEQ_LEN":0b0101,
-                                       "p_SATA_BURST_VAL":0b100,
-                                       "p_SATA_EIDLE_VAL":0b100,
-                                       "p_SATA_MAX_BURST":8,
-                                       "p_SATA_MAX_INIT":21,
-                                       "p_SATA_MAX_WAKE":7,
-                                       "p_SATA_MIN_BURST":4,
-                                       "p_SATA_MIN_INIT":12,
-                                       "p_SATA_MIN_WAKE":4,
-
-                               # RX Fabric Clock Output Control Attributes
-                                       "p_TRANS_TIME_RATE":0x0e,
-
-                               # TX Buffer Attributes
-                                       "p_TXBUF_EN":"TRUE",
-                                       "p_TXBUF_RESET_ON_RATE_CHANGE":"TRUE",
-                                       "p_TXDLY_CFG":0x1f,
-                                       "p_TXDLY_LCFG":0x030,
-                                       "p_TXDLY_TAP_CFG":0,
-                                       "p_TXPH_CFG":0x0780,
-                                       "p_TXPHDLY_CFG":0x084020,
-                                       "p_TXPH_MONITOR_SEL":0,
-                                       "p_TX_XCLK_SEL":"TXOUT",
-
-                               # FPGA TX Interface Attributes
-                                       "p_TX_DATA_WIDTH":20,
-
-                               # TX Configurable Driver Attributes
-                                       "p_TX_DEEMPH0":0,
-                                       "p_TX_DEEMPH1":0,
-                                       "p_TX_EIDLE_ASSERT_DELAY":0b110,
-                                       "p_TX_EIDLE_DEASSERT_DELAY":0b100,
-                                       "p_TX_LOOPBACK_DRIVE_HIZ":"FALSE",
-                                       "p_TX_MAINCURSOR_SEL":0,
-                                       "p_TX_DRIVE_MODE":"DIRECT",
-                                       "p_TX_MARGIN_FULL_0":0b1001110,
-                                       "p_TX_MARGIN_FULL_1":0b1001001,
-                                       "p_TX_MARGIN_FULL_2":0b1000101,
-                                       "p_TX_MARGIN_FULL_3":0b1000010,
-                                       "p_TX_MARGIN_FULL_4":0b1000000,
-                                       "p_TX_MARGIN_LOW_0":0b1000110,
-                                       "p_TX_MARGIN_LOW_1":0b1000100,
-                                       "p_TX_MARGIN_LOW_2":0b1000010,
-                                       "p_TX_MARGIN_LOW_3":0b1000000,
-                                       "p_TX_MARGIN_LOW_4":0b1000000,
-
-                               # TX Gearbox Attributes
-                                       "p_TXGEARBOX_EN":"FALSE",
-
-                               # TX Initialization and Reset Attributes
-                                       "p_TXPCSRESET_TIME":1,
-                                       "p_TXPMARESET_TIME":1,
-
-                               # TX Receiver Detection Attributes
-                                       "p_TX_RXDETECT_CFG":0x1832,
-                                       "p_TX_RXDETECT_REF":0b100,
-
-                               # CPLL Attributes
-                                       "p_CPLL_CFG":0xBC07DC,
-                                       "p_CPLL_FBDIV":4,
-                                       "p_CPLL_FBDIV_45":5,
-                                       "p_CPLL_INIT_CFG":0x00001e,
-                                       "p_CPLL_LOCK_CFG":0x01e8,
-                                       "p_CPLL_REFCLK_DIV":1,
-                                       "p_RXOUT_DIV":rxout_div,
-                                       "p_TXOUT_DIV":txout_div,
-                                       "p_SATA_CPLL_CFG":"VCO_3000MHZ",
-
-                               # RX Initialization and Reset Attributes
-                                       "p_RXDFELPMRESET_TIME":0b0001111,
-
-                               # RX Equalizer Attributes
-                                       "p_RXLPM_HF_CFG":0b00000011110000,
-                                       "p_RXLPM_LF_CFG":0b00000011110000,
-                                       "p_RX_DFE_GAIN_CFG":0x020fea,
-                                       "p_RX_DFE_H2_CFG":0b000000000000,
-                                       "p_RX_DFE_H3_CFG":0b000001000000,
-                                       "p_RX_DFE_H4_CFG":0b00011110000,
-                                       "p_RX_DFE_H5_CFG":0b00011100000,
-                                       "p_RX_DFE_KL_CFG":0b0000011111110,
-                                       "p_RX_DFE_LPM_CFG":0x0954,
-                                       "p_RX_DFE_LPM_HOLD_DURING_EIDLE":0,
-                                       "p_RX_DFE_UT_CFG":0b10001111000000000,
-                                       "p_RX_DFE_VP_CFG":0b00011111100000011,
-
-                               # Power-Down Attributes
-                                       "p_RX_CLKMUX_PD":1,
-                                       "p_TX_CLKMUX_PD":1,
-
-                               # FPGA RX Interface Attribute
-                                       "p_RX_INT_DATAWIDTH":0,
-
-                               # FPGA TX Interface Attribute
-                                       "p_TX_INT_DATAWIDTH":0,
-
-                               # TX Configurable Driver Attributes
-                                       "p_TX_QPI_STATUS_EN":0,
-
-                               # RX Equalizer Attributes
-                                       "p_RX_DFE_KL_CFG2":0b00110011000100000001100000001100,
-                                       "p_RX_DFE_XYD_CFG":0b0000000000000,
-
-                               # TX Configurable Driver Attributes
-                                       "p_TX_PREDRIVER_MODE":0,
-                       }
-
-               self.specials += \
-                       Instance("GTXE2_CHANNEL",
-                               # CPLL Ports
-                                       #o_CPLLFBCLKLOST=,
-                                       o_CPLLLOCK=self.cplllock,
-                                       i_CPLLLOCKDETCLK=0,
-                                       i_CPLLLOCKEN=1,
-                                       i_CPLLPD=0,
-                                       #o_CPLLREFCLKLOST=0,
-                                       i_CPLLREFCLKSEL=0b001,
-                                       i_CPLLRESET=self.cpllreset,
-                                       i_GTRSVD=0,
-                                       i_PCSRSVDIN=0,
-                                       i_PCSRSVDIN2=0,
-                                       i_PMARSVDIN=0,
-                                       i_PMARSVDIN2=0,
-                                       i_TSTIN=ones(20),
-                                       #o_TSTOUT=,
-
-                               # Channel
-                                       i_CLKRSVD=0,
-
-                               # Channel - Clocking Ports
-                                       i_GTGREFCLK=0,
-                                       i_GTNORTHREFCLK0=0,
-                                       i_GTNORTHREFCLK1=0,
-                                       i_GTREFCLK0=self.gtrefclk0,
-                                       i_GTREFCLK1=0,
-                                       i_GTSOUTHREFCLK0=0,
-                                       i_GTSOUTHREFCLK1=0,
-
-                               # Channel - DRP Ports
-                                       i_DRPADDR=0,
-                                       i_DRPCLK=0,
-                                       i_DRPDI=0,
-                                       #o_DRPDO=,
-                                       i_DRPEN=0,
-                                       #o_DRPRDY=,
-                                       i_DRPWE=0,
-
-                               # Clocking Ports
-                                       #o_GTREFCLKMONITOR=,
-                                       i_QPLLCLK=self.qpllclk,
-                                       i_QPLLREFCLK=self.qpllrefclk,
-                                       i_RXSYSCLKSEL=0b00,
-                                       i_TXSYSCLKSEL=0b00,
-
-                               # Digital Monitor Ports
-                                       #o_DMONITOROUT=,
-
-                               # FPGA TX Interface Datapath Configuration
-                                       i_TX8B10BEN=1,
-
-                               # Loopback Ports
-                                       i_LOOPBACK=0,
-
-                               # PCI Express Ports
-                                       #o_PHYSTATUS=,
-                                       i_RXRATE=0,
-                                       #o_RXVALID=,
-
-                               # Power-Down Ports
-                                       i_RXPD=0b00,
-                                       i_TXPD=0b00,
-
-                               # RX 8B/10B Decoder Ports
-                                       i_SETERRSTATUS=0,
-
-                               # RX Initialization and Reset Ports
-                                       i_EYESCANRESET=0,
-                                       i_RXUSERRDY=rxuserrdy,
-
-                               # RX Margin Analysis Ports
-                                       #o_EYESCANDATAERROR=,
-                                       i_EYESCANMODE=0,
-                                       i_EYESCANTRIGGER=0,
-
-                               # Receive Ports - CDR Ports
-                                       i_RXCDRFREQRESET=0,
-                                       i_RXCDRHOLD=0,
-                                       o_RXCDRLOCK=rxcdrlock,
-                                       i_RXCDROVRDEN=0,
-                                       i_RXCDRRESET=0,
-                                       i_RXCDRRESETRSV=0,
-
-                               # Receive Ports - Clock Correction Ports
-                                       #o_RXCLKCORCNT=,
-
-                               # Receive Ports - FPGA RX Interface Datapath Configuration
-                                       i_RX8B10BEN=1,
-
-                               # Receive Ports - FPGA RX Interface Ports
-                                       i_RXUSRCLK=self.rxusrclk,
-                                       i_RXUSRCLK2=self.rxusrclk2,
-
-                               # Receive Ports - FPGA RX interface Ports
-                                       o_RXDATA=self.rxdata,
-
-                               # Receive Ports - Pattern Checker Ports
-                                       #o_RXPRBSERR=,
-                                       i_RXPRBSSEL=0,
-
-                               # Receive Ports - Pattern Checker ports
-                                       i_RXPRBSCNTRESET=0,
-
-                               # Receive Ports - RX  Equalizer Ports
-                                       i_RXDFEXYDEN=0,
-                                       i_RXDFEXYDHOLD=0,
-                                       i_RXDFEXYDOVRDEN=0,
-
-                               # Receive Ports - RX 8B/10B Decoder Ports
-                                       #o_RXDISPERR=,
-                                       #o_RXNOTINTABLE=,
-
-                               # Receive Ports - RX AFE
-                                       i_GTXRXP=pads.rxp,
-                                       i_GTXRXN=pads.rxn,
-
-                               # Receive Ports - RX Buffer Bypass Ports
-                                       i_RXBUFRESET=0,
-                                       #o_RXBUFSTATUS=,
-                                       i_RXDDIEN=0,
-                                       i_RXDLYBYPASS=1,
-                                       i_RXDLYEN=0,
-                                       i_RXDLYOVRDEN=0,
-                                       i_RXDLYSRESET=0,
-                                       #o_RXDLYSRESETDONE=0,
-                                       i_RXPHALIGN=0,
-                                       #o_RXPHALIGNDONE=,
-                                       i_RXPHALIGNEN=0,
-                                       i_RXPHDLYPD=0,
-                                       i_RXPHDLYRESET=0,
-                                       #o_RXPHMONITOR=,
-                                       i_RXPHOVRDEN=0,
-                                       #o_RXPHSLIPMONITOR=,
-                                       #o_RXSTATUS=,
-
-                               # Receive Ports - RX Byte and Word Alignment Ports
-                                       o_RXBYTEISALIGNED=self.rxbyteisaligned,
-                                       #o_RXBYTEREALIGN=,
-                                       #o_RXCOMMADET=,
-                                       i_RXCOMMADETEN=1,
-                                       i_RXMCOMMAALIGNEN=1,
-                                       i_RXPCOMMAALIGNEN=1,
-
-                               # Receive Ports - RX Channel Bonding Ports
-                                       #o_RXCHANBONDSEQ=,
-                                       i_RXCHBONDEN=0,
-                                       i_RXCHBONDLEVEL=0,
-                                       i_RXCHBONDMASTER=0,
-                                       #o_RXCHBONDO=,
-                                       i_RXCHBONDSLAVE=0,
-
-                               # Receive Ports - RX Channel Bonding Ports
-                                       #o_RXCHANISALIGNED=,
-                                       #o_RXCHANREALIGN=,
-
-                               # Receive Ports - RX Equalizer Ports
-                                       i_RXDFEAGCHOLD=0,
-                                       i_RXDFEAGCOVRDEN=0,
-                                       i_RXDFECM1EN=0,
-                                       i_RXDFELFHOLD=0,
-                                       i_RXDFELFOVRDEN=1,
-                                       i_RXDFELPMRESET=0,
-                                       i_RXDFETAP2HOLD=0,
-                                       i_RXDFETAP2OVRDEN=0,
-                                       i_RXDFETAP3HOLD=0,
-                                       i_RXDFETAP3OVRDEN=0,
-                                       i_RXDFETAP4HOLD=0,
-                                       i_RXDFETAP4OVRDEN=0,
-                                       i_RXDFETAP5HOLD=0,
-                                       i_RXDFETAP5OVRDEN=0,
-                                       i_RXDFEUTHOLD=0,
-                                       i_RXDFEUTOVRDEN=0,
-                                       i_RXDFEVPHOLD=0,
-                                       i_RXDFEVPOVRDEN=0,
-                                       i_RXDFEVSEN=0,
-                                       i_RXLPMLFKLOVRDEN=0,
-                                       #o_RXMONITOROUT=,
-                                       i_RXMONITORSEL=0b00,
-                                       i_RXOSHOLD=0,
-                                       i_RXOSOVRDEN=0,
-
-                               # Receive Ports - RX Equilizer Ports
-                                       i_RXLPMHFHOLD=0,
-                                       i_RXLPMHFOVRDEN=0,
-                                       i_RXLPMLFHOLD=0,
-
-                               # Receive Ports - RX Fabric ClocK Output Control Ports
-                                       #o_RXRATEDONE=,
-
-                               # Receive Ports - RX Fabric Output Control Ports
-                                       o_RXOUTCLK=self.rxoutclk,
-                                       #o_RXOUTCLKFABRIC=,
-                                       #o_RXOUTCLKPCS=,
-                                       i_RXOUTCLKSEL=0b010,
-
-                               # Receive Ports - RX Gearbox Ports
-                                       #o_RXDATAVALID=,
-                                       #o_RXHEADER=,
-                                       #o_RXHEADERVALID=,
-                                       #o_RXSTARTOFSEQ=,
-
-                               # Receive Ports - RX Gearbox Ports
-                                       i_RXGEARBOXSLIP=0,
-
-                               # Receive Ports - RX Initialization and Reset Ports
-                                       i_GTRXRESET=self.gtrxreset,
-                                       i_RXOOBRESET=0,
-                                       i_RXPCSRESET=0,
-                                       i_RXPMARESET=self.pmarxreset,
-
-                               # Receive Ports - RX Margin Analysis ports
-                                       i_RXLPMEN=0,
-
-                               # Receive Ports - RX OOB Signaling ports
-                                       #o_RXCOMSASDET=,
-                                       o_RXCOMWAKEDET=rxcomwakedet,
-
-                               # Receive Ports - RX OOB Signaling ports
-                                       o_RXCOMINITDET=rxcominitdet,
-
-                               # Receive Ports - RX OOB signalling Ports
-                                       o_RXELECIDLE=rxelecidle,
-                                       i_RXELECIDLEMODE=0b00,
-
-                               # Receive Ports - RX Polarity Control Ports
-                                       i_RXPOLARITY=0,
-
-                               # Receive Ports - RX gearbox ports
-                                       i_RXSLIDE=0,
-
-                               # Receive Ports - RX8B/10B Decoder Ports
-                                       #o_RXCHARISCOMMA=,
-                                       o_RXCHARISK=self.rxcharisk,
-
-                               # Receive Ports - Rx Channel Bonding Ports
-                                       i_RXCHBONDI=0,
-
-                               # Receive Ports -RX Initialization and Reset Ports
-                                       o_RXRESETDONE=rxresetdone,
-
-                               # Rx AFE Ports
-                                       i_RXQPIEN=0,
-                                       #o_RXQPISENN=,
-                                       #o_RXQPISENP=,
-
-                               # TX Buffer Bypass Ports
-                                       i_TXPHDLYTSTCLK=0,
-
-                               # TX Configurable Driver Ports
-                                       i_TXPOSTCURSOR=0,
-                                       i_TXPOSTCURSORINV=0,
-                                       i_TXPRECURSOR=0,
-                                       i_TXPRECURSORINV=0,
-                                       i_TXQPIBIASEN=0,
-                                       i_TXQPISTRONGPDOWN=0,
-                                       i_TXQPIWEAKPUP=0,
-
-                               # TX Initialization and Reset Ports
-                                       i_CFGRESET=0,
-                                       i_GTTXRESET=self.gttxreset,
-                                       #o_PCSRSVDOUT=,
-                                       i_TXUSERRDY=txuserrdy,
-
-                               # Transceiver Reset Mode Operation
-                                       i_GTRESETSEL=0,
-                                       i_RESETOVRD=0,
-
-                               # Transmit Ports - 8b10b Encoder Control Ports
-                                       i_TXCHARDISPMODE=0,
-                                       i_TXCHARDISPVAL=0,
-
-                               # Transmit Ports - FPGA TX Interface Ports
-                                       i_TXUSRCLK=self.txusrclk,
-                                       i_TXUSRCLK2=self.txusrclk2,
-
-                               # Transmit Ports - PCI Express Ports
-                                       i_TXELECIDLE=txelecidle,
-                                       i_TXMARGIN=0,
-                                       i_TXRATE=txrate,
-                                       i_TXSWING=0,
-
-                               # Transmit Ports - Pattern Generator Ports
-                                       i_TXPRBSFORCEERR=0,
-
-                               # Transmit Ports - TX Buffer Bypass Ports
-                                       i_TXDLYBYPASS=1,
-                                       i_TXDLYEN=0,
-                                       i_TXDLYHOLD=0,
-                                       i_TXDLYOVRDEN=0,
-                                       i_TXDLYSRESET=0,
-                                       #o_TXDLYSRESETDONE=,
-                                       i_TXDLYUPDOWN=0,
-                                       i_TXPHALIGN=0,
-                                       #o_TXPHALIGNDONE=txphaligndone,
-                                       i_TXPHALIGNEN=0,
-                                       i_TXPHDLYPD=0,
-                                       i_TXPHDLYRESET=0,
-                                       i_TXPHINIT=0,
-                                       #o_TXPHINITDONE=,
-                                       i_TXPHOVRDEN=0,
-
-                               # Transmit Ports - TX Buffer Ports
-                                       #o_TXBUFSTATUS=,
-
-                               # Transmit Ports - TX Configurable Driver Ports
-                                       i_TXBUFDIFFCTRL=0b100,
-                                       i_TXDEEMPH=0,
-                                       i_TXDIFFCTRL=0b1000,
-                                       i_TXDIFFPD=0,
-                                       i_TXINHIBIT=0,
-                                       i_TXMAINCURSOR=0,
-                                       i_TXPISOPD=0,
-
-                               # Transmit Ports - TX Data Path interface
-                                       i_TXDATA=self.txdata,
-
-                               # Transmit Ports - TX Driver and OOB signaling
-                                       o_GTXTXP=pads.txp,
-                                       o_GTXTXN=pads.txn,
-
-                               # Transmit Ports - TX Fabric Clock Output Control Ports
-                                       o_TXOUTCLK=self.txoutclk,
-                                       #o_TXOUTCLKFABRIC=,
-                                       #o_TXOUTCLKPCS=,
-                                       i_TXOUTCLKSEL=0b11, #??
-                                       #o_TXRATEDONE=,
-                               # Transmit Ports - TX Gearbox Ports
-                                       i_TXCHARISK=self.txcharisk,
-                                       #o_TXGEARBOXREADY=,
-                                       i_TXHEADER=0,
-                                       i_TXSEQUENCE=0,
-                                       i_TXSTARTSEQ=0,
-
-                               # Transmit Ports - TX Initialization and Reset Ports
-                                       i_TXPCSRESET=0,
-                                       i_TXPMARESET=0,
-                                       o_TXRESETDONE=txresetdone,
-
-                               # Transmit Ports - TX OOB signalling Ports
-                                       o_TXCOMFINISH=txcomfinish,
-                                       i_TXCOMINIT=txcominit,
-                                       i_TXCOMSAS=0,
-                                       i_TXCOMWAKE=txcomwake,
-                                       i_TXPDELECIDLEMODE=0,
-
-                               # Transmit Ports - TX Polarity Control Ports
-                                       i_TXPOLARITY=0,
-
-                               # Transmit Ports - TX Receiver Detection Ports
-                                       i_TXDETECTRX=0,
-
-                               # Transmit Ports - TX8b/10b Encoder Ports
-                                       i_TX8B10BBYPASS=0,
-
-                               # Transmit Ports - pattern Generator Ports
-                                       i_TXPRBSSEL=0,
-
-                               # Tx Configurable Driver  Ports
-                                       #o_TXQPISENN=,
-                                       #o_TXQPISENP=,
-
-                                       **gtxe2_channel_parameters
-                       )
diff --git a/lib/sata/test/Makefile b/lib/sata/test/Makefile
deleted file mode 100644 (file)
index 0285918..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-MSCDIR = ../../../
-PYTHON = python3
-
-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
-
-scrambler_tb:
-       $(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
-       $(CMD) scrambler_tb.py
-
-cont_tb:
-       $(CMD) cont_tb.py
-
-link_tb:
-       $(CMD) link_tb.py
-
-command_tb:
-       $(CMD) command_tb.py
-
-bist_tb:
-       $(CMD) bist_tb.py
-
-clean:
-       rm crc scrambler *.vcd
diff --git a/lib/sata/test/bist_tb.py b/lib/sata/test/bist_tb.py
deleted file mode 100644 (file)
index 72c9997..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-from lib.sata.common import *
-from lib.sata import SATACON
-from lib.sata.bist import SATABISTGenerator, SATABISTChecker
-
-from lib.sata.test.hdd import *
-from lib.sata.test.common import *
-
-class TB(Module):
-       def __init__(self):
-               self.hdd = HDD(
-                               link_debug=False, link_random_level=0,
-                               transport_debug=False, transport_loopback=False,
-                               hdd_debug=True)
-               self.controller = SATACON(self.hdd.phy)
-               self.generator = SATABISTGenerator(self.controller.crossbar.get_port())
-               self.checker = SATABISTChecker(self.controller.crossbar.get_port())
-
-       def gen_simulation(self, selfp):
-               hdd = self.hdd
-               hdd.malloc(0, 64)
-               selfp.generator.sector = 0
-               selfp.generator.count = 17
-               selfp.checker.sector = 0
-               selfp.checker.count = 17
-               while True:
-                       selfp.generator.start = 1
-                       yield
-                       selfp.generator.start = 0
-                       yield
-                       while selfp.generator.done == 0:
-                               yield
-                       selfp.checker.start = 1
-                       yield
-                       selfp.checker.start = 0
-                       yield
-                       while selfp.checker.done == 0:
-                               yield
-                       print("errors {}".format(selfp.checker.errors))
-                       selfp.generator.sector += 1
-                       selfp.generator.count = max((selfp.generator.count + 1)%8, 1)
-                       selfp.checker.sector += 1
-                       selfp.checker.count = max((selfp.checker.count + 1)%8, 1)
-
-if __name__ == "__main__":
-       run_simulation(TB(), ncycles=8192*2, vcd_name="my.vcd", keep_files=True)
diff --git a/lib/sata/test/command_tb.py b/lib/sata/test/command_tb.py
deleted file mode 100644 (file)
index 4470dd8..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-from lib.sata.common import *
-from lib.sata.link import SATALink
-from lib.sata.transport import SATATransport
-from lib.sata.command import SATACommand
-
-from lib.sata.test.hdd import *
-from lib.sata.test.common import *
-
-class CommandTXPacket(list):
-       def __init__(self, write=0, read=0, sector=0, count=0, data=[]):
-               self.ongoing = False
-               self.done = False
-               self.write = write
-               self.read = read
-               self.sector = sector
-               self.count = count
-               for d in data:
-                       self.append(d)
-
-class CommandStreamer(PacketStreamer):
-       def __init__(self):
-               PacketStreamer.__init__(self, command_tx_description(32), CommandTXPacket)
-
-       def do_simulation(self, selfp):
-               PacketStreamer.do_simulation(self, selfp)
-               selfp.source.write = self.packet.write
-               selfp.source.read = self.packet.read
-               selfp.source.sector = self.packet.sector
-               selfp.source.count = self.packet.count
-
-class CommandRXPacket(list):
-       def __init__(self):
-               self.ongoing = False
-               self.done = False
-               self.write = 0
-               self.read = 0
-               self.success = 0
-               self.failed = 0
-
-class CommandLogger(PacketLogger):
-       def __init__(self):
-               PacketLogger.__init__(self, command_rx_description(32), CommandRXPacket)
-
-       def do_simulation(self, selfp):
-               selfp.sink.ack = 1
-               if selfp.sink.stb == 1 and selfp.sink.sop == 1:
-                       self.packet = CommandRXPacket()
-                       self.packet.write = selfp.sink.write
-                       self.packet.read = selfp.sink.read
-                       self.packet.sucess = selfp.sink.success
-                       self.packet.failed = selfp.sink.failed
-                       self.packet.append(selfp.sink.data)
-               elif selfp.sink.stb:
-                       self.packet.append(selfp.sink.data)
-               if selfp.sink.stb == 1 and selfp.sink.eop == 1:
-                       self.packet.done = True
-
-class TB(Module):
-       def __init__(self):
-               self.hdd = HDD(
-                               link_debug=False, link_random_level=50,
-                               transport_debug=False, transport_loopback=False,
-                               hdd_debug=True)
-               self.link = SATALink(self.hdd.phy)
-               self.transport = SATATransport(self.link)
-               self.command = SATACommand(self.transport)
-
-               self.streamer = CommandStreamer()
-               self.streamer_randomizer = Randomizer(command_tx_description(32), level=50)
-
-               self.logger = CommandLogger()
-               self.logger_randomizer = Randomizer(command_rx_description(32), level=50)
-
-               self.pipeline = Pipeline(
-                       self.streamer,
-                       self.streamer_randomizer,
-                       self.command,
-                       self.logger_randomizer,
-                       self.logger
-               )
-
-       def gen_simulation(self, selfp):
-               hdd = self.hdd
-               hdd.malloc(0, 64)
-               write_data = [i for i in range(sectors2dwords(2))]
-               write_len = dwords2sectors(len(write_data))
-               write_packet = CommandTXPacket(write=1, sector=2, count=write_len, data=write_data)
-               yield from self.streamer.send(write_packet)
-               yield from self.logger.receive()
-               read_packet = CommandTXPacket(read=1, sector=2, count=write_len)
-               yield from self.streamer.send(read_packet)
-               yield from self.logger.receive()
-               read_data = self.logger.packet
-
-               # check results
-               s, l, e = check(write_data, read_data)
-               print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-if __name__ == "__main__":
-       run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
diff --git a/lib/sata/test/common.py b/lib/sata/test/common.py
deleted file mode 100644 (file)
index e0ba6fe..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-import random, copy
-
-from migen.sim.generic import run_simulation
-
-from lib.sata.common import *
-
-def seed_to_data(seed, random=True):
-       if random:
-               return (seed * 0x31415979 + 1) & 0xffffffff
-       else:
-               return seed
-
-def check(p1, p2):
-       p1 = copy.deepcopy(p1)
-       p2 = copy.deepcopy(p2)
-       if isinstance(p1, int):
-               return 0, 1, int(p1 != p2)
-       else:
-               if len(p1) >= len(p2):
-                       ref, res = p1, p2
-               else:
-                       ref, res = p2, p1
-               shift = 0
-               while((ref[0] != res[0]) and (len(res)>1)):
-                       res.pop(0)
-                       shift += 1
-               length = min(len(ref), len(res))
-               errors = 0
-               for i in range(length):
-                       if ref.pop(0) != res.pop(0):
-                               errors += 1
-               return shift, length, errors
-
-def randn(max_n):
-       return random.randint(0, max_n-1)
-
-class PacketStreamer(Module):
-       def __init__(self, description, packet_class):
-               self.source = Source(description)
-               ###
-               self.packets = []
-               self.packet = packet_class()
-               self.packet.done = 1
-
-               self.source_data = 0
-
-       def send(self, packet, blocking=True):
-               packet = copy.deepcopy(packet)
-               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 not self.packet.ongoing and not self.packet.done:
-                       selfp.source.stb = 1
-                       if self.source.description.packetized:
-                               selfp.source.sop = 1
-                       if len(self.packet) > 0:
-                               self.source_data = self.packet.pop(0)
-                               if hasattr(selfp.source, "data"):
-                                       selfp.source.data = self.source_data
-                               else:
-                                       selfp.source.d = self.source_data
-                       self.packet.ongoing = True
-               elif selfp.source.stb == 1 and selfp.source.ack == 1:
-                       if self.source.description.packetized:
-                               selfp.source.sop = 0
-                               selfp.source.eop = (len(self.packet) == 1)
-                       if len(self.packet) > 0:
-                               selfp.source.stb = 1
-                               self.source_data = self.packet.pop(0)
-                               if hasattr(selfp.source, "data"):
-                                       selfp.source.data = self.source_data
-                               else:
-                                       selfp.source.d = self.source_data
-                       else:
-                               self.packet.done = 1
-                               selfp.source.stb = 0
-
-class PacketLogger(Module):
-       def __init__(self, description, packet_class):
-               self.sink = Sink(description)
-               ###
-               self.packet_class = packet_class
-               self.packet = packet_class()
-
-       def receive(self, length=None):
-               self.packet.done = 0
-               if length is None:
-                       while self.packet.done == 0:
-                               yield
-               else:
-                       while length > len(self.packet):
-                               yield
-
-       def do_simulation(self, selfp):
-               selfp.sink.ack = 1
-               if self.sink.description.packetized:
-                       if selfp.sink.stb == 1 and selfp.sink.sop == 1:
-                               self.packet = self.packet_class()
-               if selfp.sink.stb:
-                       if hasattr(selfp.sink, "data"):
-                               self.packet.append(selfp.sink.data)
-                       else:
-                               self.packet.append(selfp.sink.d)
-               if self.sink.description.packetized:
-                       if selfp.sink.stb == 1 and selfp.sink.eop == 1:
-                               self.packet.done = True
-
-class Randomizer(Module):
-       def __init__(self, description, level=0):
-               self.level = level
-
-               self.sink = Sink(description)
-               self.source = Source(description)
-
-               self.run = Signal()
-
-               self.comb += \
-                       If(self.run,
-                               Record.connect(self.sink, self.source)
-                       ).Else(
-                               self.source.stb.eq(0),
-                               self.sink.ack.eq(0),
-                       )
-
-       def do_simulation(self, selfp):
-               n = randn(100)
-               if n < self.level:
-                       selfp.run = 0
-               else:
-                       selfp.run = 1
diff --git a/lib/sata/test/cont_tb.py b/lib/sata/test/cont_tb.py
deleted file mode 100644 (file)
index 61c800d..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-from lib.sata.common import *
-from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
-
-from lib.sata.test.common import *
-
-class ContPacket(list):
-       def __init__(self, data=[]):
-               self.ongoing = False
-               self.done = False
-               for d in data:
-                       self.append(d)
-
-class ContStreamer(PacketStreamer):
-       def __init__(self):
-               PacketStreamer.__init__(self, phy_description(32), ContPacket)
-
-       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 ContLogger(PacketLogger):
-       def __init__(self):
-               PacketLogger.__init__(self, phy_description(32), ContPacket)
-
-class TB(Module):
-       def __init__(self):
-               self.streamer = ContStreamer()
-               self.streamer_randomizer = Randomizer(phy_description(32), level=50)
-               self.inserter = SATACONTInserter(phy_description(32))
-               self.remover = SATACONTRemover(phy_description(32))
-               self.logger_randomizer = Randomizer(phy_description(32), level=50)
-               self.logger = ContLogger()
-
-               self.pipeline = Pipeline(
-                       self.streamer,
-                       self.streamer_randomizer,
-                       self.inserter,
-                       self.remover,
-                       self.logger_randomizer,
-                       self.logger
-               )
-
-       def gen_simulation(self, selfp):
-               test_packet = ContPacket([
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["ALIGN"],
-                       primitives["ALIGN"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       #primitives["SYNC"],
-                       0x00000000,
-                       0x00000001,
-                       0x00000002,
-                       0x00000003,
-                       0x00000004,
-                       0x00000005,
-                       0x00000006,
-                       0x00000007,
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["ALIGN"],
-                       primitives["ALIGN"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["SYNC"],
-                       primitives["SYNC"]]*4
-                       )
-               streamer_packet = ContPacket(test_packet)
-               yield from self.streamer.send(streamer_packet)
-               yield from self.logger.receive(len(test_packet))
-               #for d in self.logger.packet:
-               #       print("%08x" %d)
-
-               # 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=1024, vcd_name="my.vcd", keep_files=True)
diff --git a/lib/sata/test/crc.c b/lib/sata/test/crc.c
deleted file mode 100644 (file)
index 75576b5..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-// Adapted from SATA specification
-/****************************************************************************/
-/*                                                                          */
-/* crc.c                                                                    */
-/*                                                                          */
-/* This sample code reads standard in for a sequence of 32 bit values       */
-/* formatted in hexadecimal with a leading "0x" (e.g. 0xDEADBEEF). The      */
-/* code calculates the Serial ATA CRC for the input data stream. The        */
-/* generator polynomial used is:                                            */
-/* 32 26 23 22 16 12 11 10 8 7 5 4 2                                        */
-/* G(x) = x + x + x + x + x + x + x + x + x + x + x + x + x + x + 1         */
-/*                                                                          */
-/* This sample code uses a parallel implementation of the CRC calculation   */
-/* circuit that is suitable for implementation in hardware. A block         */
-/* diagram of the circuit being emulated is shown below.                    */
-/*                                                                          */
-/*                   +---+          +---+          +---+                    */
-/* Data_In --------->|   |          |   |          | R |                    */
-/*                   | + |--------->| * |--------->| e |----+               */
-/*             +---->|   |          |   |          | g |    |               */
-/*             |     +---+          +---+          +---+    |               */
-/*             |                                            |               */
-/*             |                                            |               */
-/*             +--------------------------------------------+               */
-/*                                                                          */
-/* The CRC value is initialized to 0x52325032 as defined in the Serial ATA  */
-/* specification.                                                           */
-/*                                                                          */
-/****************************************************************************/
-
-
-
-#include <stdlib.h>
-#include <stdio.h>
-int main(int argc, char *argv[])
-{
-   int i;
-   unsigned int data_count;
-   unsigned int crc;
-   unsigned int data_in;
-   unsigned char crc_bit[32];
-   unsigned char new_bit[32];
-
-   crc = 0x52325032;
-   data_count = 0;
-
-   while((scanf(" 0x%8x", &data_in) == 1) && (!scanf("exit"))) {
-      data_count++;
-      /* Add the data_in value to the current value of the CRC held in the  */
-      /* "register". The addition is performed modulo two (XOR).            */
-      crc ^= data_in;
-      /* Expand the value of the CRC held in the register to 32 individual  */
-      /* bits for easy manipulation. */
-      for (i = 0; i < 32; ++i)  {
-         crc_bit[i] = (crc >> i) & 0x01;
-      }
-      /* The following 32 assignments perform the function of the box       */
-      /* labeled "*" in the block diagram above. The new_bit array is a     */
-      /* temporary holding place for the new CRC value being calculated.    */
-      /* Note that there are lots of shared terms in the assignments below. */
-      new_bit[31] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^
-                    crc_bit[23] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[5];
-      new_bit[30] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^
-                    crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[4];
-      new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^
-                    crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[3];
-      new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^
-                    crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[2];
-      new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^
-                    crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[1];
-      new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^
-                    crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6]  ^ crc_bit[4]  ^ crc_bit[3]  ^
-                    crc_bit[0];
-      new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^
-                    crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8]  ^ crc_bit[3]  ^ crc_bit[2];
-      new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^
-                    crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7]  ^ crc_bit[2]  ^ crc_bit[1];
-      new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^
-                    crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9]  ^ crc_bit[6]  ^ crc_bit[1]  ^ crc_bit[0];
-      new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^
-                    crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9]  ^ crc_bit[0];
-      new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^
-                    crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9]  ^ crc_bit[5];
-      new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^
-                    crc_bit[16] ^ crc_bit[12] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[4];
-      new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^
-                    crc_bit[15] ^ crc_bit[11] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[3];
-      new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^
-                    crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[2];
-      new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^
-                    crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[1];
-      new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^
-                    crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[0];
-      new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^
-                    crc_bit[15] ^ crc_bit[12] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[5]  ^ crc_bit[4]  ^
-                    crc_bit[3];
-      new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^
-                    crc_bit[14] ^ crc_bit[11] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[4]  ^ crc_bit[3]  ^
-                    crc_bit[2];
-      new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^
-                    crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[3]  ^
-                    crc_bit[2]  ^ crc_bit[1];
-      new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^
-                    crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[4]  ^
-                    crc_bit[2]  ^ crc_bit[1]  ^ crc_bit[0];
-      new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^
-                    crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9]  ^ crc_bit[4]  ^
-                    crc_bit[3]  ^ crc_bit[1]  ^ crc_bit[0];
-      new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^
-                    crc_bit[13] ^ crc_bit[9]  ^ crc_bit[5]  ^ crc_bit[3]  ^ crc_bit[2]  ^ crc_bit[0];
-      new_bit[9]  = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^
-                    crc_bit[9]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[2]  ^ crc_bit[1];
-      new_bit[8]  = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^
-                    crc_bit[10] ^ crc_bit[8]  ^ crc_bit[4]  ^ crc_bit[3]  ^ crc_bit[1]  ^ crc_bit[0];
-      new_bit[7]  = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^
-                    crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[5]  ^ crc_bit[3]  ^
-                    crc_bit[2]  ^ crc_bit[0];
-      new_bit[6]  = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^
-                    crc_bit[11] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[2]  ^
-                    crc_bit[1];
-      new_bit[5]  = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^
-                    crc_bit[10] ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[3]  ^ crc_bit[1]  ^
-                    crc_bit[0];
-      new_bit[4]  = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^
-                    crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8]  ^ crc_bit[6]  ^ crc_bit[4]  ^
-                    crc_bit[3]  ^ crc_bit[2]  ^ crc_bit[0];
-      new_bit[3]  = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^
-                    crc_bit[14] ^ crc_bit[10] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[3]  ^ crc_bit[2]  ^
-                    crc_bit[1];
-      new_bit[2]  = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^
-                    crc_bit[14] ^ crc_bit[13] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[2]  ^
-                    crc_bit[1]  ^ crc_bit[0];
-      new_bit[1]  = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^
-                    crc_bit[11] ^ crc_bit[9]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[1]  ^ crc_bit[0];
-      new_bit[0]  = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^
-                    crc_bit[16] ^ crc_bit[12] ^ crc_bit[10] ^ crc_bit[9]  ^ crc_bit[6]  ^ crc_bit[0];
-
-      /* The new CRC value has been calculated as individual bits in the */
-      /* new_bit array. Re-assembled it into a 32 bit value and "clock" it */
-      /* into the "register". */
-      crc = 0;
-      for (i = 31; i >= 0; --i)  {
-         crc = crc << 1;
-         crc |= new_bit[i];
-      }
-   }
-   printf("%08x\n", crc);
-   return 0;
-}
diff --git a/lib/sata/test/crc_tb.py b/lib/sata/test/crc_tb.py
deleted file mode 100644 (file)
index 2b974fb..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-import subprocess
-
-from lib.sata.common import *
-from lib.sata.link.crc import *
-
-from lib.sata.test.common import *
-
-class TB(Module):
-       def __init__(self, length, random):
-               self.crc = SATACRC()
-               self.length = length
-               self.random = random
-
-       def get_c_crc(self, datas):
-               stdin = ""
-               for data in datas:
-                       stdin += "0x%08x " %data
-               stdin += "exit"
-               with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
-                       process.stdin.write(stdin.encode("ASCII"))
-                       out, err = process.communicate()
-               return int(out.decode("ASCII"), 16)
-
-       def gen_simulation(self, selfp):
-               # init CRC
-               selfp.crc.d = 0
-               selfp.crc.ce = 1
-               selfp.crc.reset = 1
-               yield
-               selfp.crc.reset = 0
-
-               # feed CRC with datas
-               datas = []
-               for i in range(self.length):
-                       data = seed_to_data(i, self.random)
-                       datas.append(data)
-                       selfp.crc.d = data
-                       yield
-
-               # log results
-               yield
-               sim_crc = selfp.crc.value
-
-               # stop
-               selfp.crc.ce = 0
-               for i in range(32):
-                       yield
-
-               # get C core reference
-               c_crc = self.get_c_crc(datas)
-
-               # check results
-               s, l, e = check(c_crc, sim_crc)
-               print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-if __name__ == "__main__":
-       from migen.sim.generic import run_simulation
-       length = 8192
-       run_simulation(TB(length, True), ncycles=length+100, vcd_name="my.vcd")
diff --git a/lib/sata/test/hdd.py b/lib/sata/test/hdd.py
deleted file mode 100644 (file)
index e390d81..0000000
+++ /dev/null
@@ -1,511 +0,0 @@
-import subprocess
-import math
-
-from lib.sata.common import *
-from lib.sata.test.common import *
-
-def print_with_prefix(s, prefix=""):
-       if not isinstance(s, str):
-               s = s.__repr__()
-       s = s.split("\n")
-       for l in s:
-               print(prefix + l)
-
-# PHY Layer model
-class PHYDword:
-       def __init__(self, dat=0):
-               self.dat = dat
-               self.start = 1
-               self.done = 0
-
-class PHYSource(Module):
-       def __init__(self):
-               self.source = Source(phy_description(32))
-               ###
-               self.dword = PHYDword()
-
-       def send(self, dword):
-               self.dword = dword
-
-       def do_simulation(self, selfp):
-               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
-
-class PHYSink(Module):
-       def __init__(self):
-               self.sink = Sink(phy_description(32))
-               ###
-               self.dword = PHYDword()
-
-       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 PHYLayer(Module):
-       def __init__(self):
-
-               self.rx = PHYSink()
-               self.tx = PHYSource()
-
-               self.source = self.tx.source
-               self.sink = self.rx.sink
-
-       def send(self, dword):
-               packet = PHYDword(dword)
-               self.tx.send(packet)
-
-       def receive(self):
-               yield from self.rx.receive()
-
-       def __repr__(self):
-               receiving = "%08x " %self.rx.dword.dat
-               receiving += decode_primitive(self.rx.dword.dat)
-               receiving += " "*(16-len(receiving))
-
-               sending = "%08x " %self.tx.dword.dat
-               sending += decode_primitive(self.tx.dword.dat)
-               sending += " "*(16-len(sending))
-
-               return receiving + sending
-
-# Link Layer model
-def print_link(s):
-       print_with_prefix(s, "[LNK]: ")
-
-def import_scrambler_datas():
-       with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
-               process.stdin.write("0x10000".encode("ASCII"))
-               out, err = process.communicate()
-       return [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]]
-
-class LinkPacket(list):
-       def __init__(self, init=[]):
-               self.ongoing = False
-               self.done = False
-               self.scrambled_datas = import_scrambler_datas()
-               for dword in init:
-                       self.append(dword)
-
-class LinkRXPacket(LinkPacket):
-       def descramble(self):
-               for i in range(len(self)):
-                       self[i] = self[i] ^ self.scrambled_datas[i]
-
-       def check_crc(self):
-               stdin = ""
-               for v in self[:-1]:
-                       stdin += "0x%08x " %v
-               stdin += "exit"
-               with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
-                       process.stdin.write(stdin.encode("ASCII"))
-                       out, err = process.communicate()
-               crc = int(out.decode("ASCII"), 16)
-               r = (self[-1] == crc)
-               self.pop()
-               return r
-
-       def decode(self):
-               self.descramble()
-               return self.check_crc()
-
-class LinkTXPacket(LinkPacket):
-       def insert_crc(self):
-               stdin = ""
-               for v in self:
-                       stdin += "0x%08x " %v
-               stdin += "exit"
-               with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
-                       process.stdin.write(stdin.encode("ASCII"))
-                       out, err = process.communicate()
-               crc = int(out.decode("ASCII"), 16)
-               self.append(crc)
-
-       def scramble(self):
-               for i in range(len(self)):
-                       self[i] = self[i] ^ self.scrambled_datas[i]
-
-       def encode(self):
-               self.insert_crc()
-               self.scramble()
-
-class LinkLayer(Module):
-       def  __init__(self, phy, debug=False, random_level=0):
-               self.phy = phy
-               self.debug = debug
-               self.random_level = random_level
-               self.tx_packets = []
-               self.tx_packet = LinkTXPacket()
-               self.rx_packet = LinkRXPacket()
-
-               self.rx_cont = False
-               self.rx_last = 0
-               self.tx_cont = False
-               self.tx_cont_nb = -1
-               self.tx_lasts = [0, 0, 0]
-
-               self.scrambled_datas = import_scrambler_datas()
-
-               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
-
-       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":
-                       if dword == primitives["HOLD"]:
-                               self.phy.send(primitives["HOLDA"])
-                       else:
-                               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
-                       if self.tx_packet.done:
-                               self.phy.send(primitives["SYNC"])
-
-       def insert_cont(self):
-               self.tx_lasts.pop(0)
-               self.tx_lasts.append(self.phy.tx.dword.dat)
-               self.tx_cont = True
-               for i in range(3):
-                       if not is_primitive(self.tx_lasts[i]):
-                               self.tx_cont = False
-                       if self.tx_lasts[i] != self.tx_lasts[0]:
-                               self.tx_cont = False
-               if self.tx_cont:
-                       if self.tx_cont_nb == 0:
-                               self.phy.send(primitives["CONT"])
-                       else:
-                               self.phy.send(self.scrambled_datas[self.tx_cont_nb])
-                       self.tx_cont_nb += 1
-               else:
-                       self.tx_cont_nb = 0
-
-       def remove_cont(self, dword):
-               if dword == primitives["HOLD"]:
-                       if self.rx_cont:
-                               self.tx_lasts = [0, 0, 0]
-               if dword == primitives["CONT"]:
-                       self.rx_cont = True
-               elif is_primitive(dword):
-                       self.rx_last = dword
-                       self.rx_cont = False
-               if self.rx_cont:
-                       dword = self.rx_last
-               return dword
-
-       def callback(self, dword):
-               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"]:
-                       pass
-               elif self.rx_packet.ongoing:
-                       if dword != primitives["HOLD"]:
-                               n = randn(100)
-                               if n < self.random_level:
-                                       self.phy.send(primitives["HOLD"])
-                               else:
-                                       self.phy.send(primitives["R_IP"])
-                               if not is_primitive(dword):
-                                               self.rx_packet.append(dword)
-               elif dword == primitives["SOF"]:
-                       self.rx_packet = LinkRXPacket()
-                       self.rx_packet.ongoing = True
-
-       def gen_simulation(self, selfp):
-               self.tx_packet.done = True
-               self.phy.send(primitives["SYNC"])
-               while True:
-                       yield from self.phy.receive()
-                       if self.debug:
-                               print_link(self.phy)
-                       self.phy.send(primitives["SYNC"])
-                       rx_dword = self.phy.rx.dword.dat
-                       rx_dword = self.remove_cont(rx_dword)
-                       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(rx_dword)
-                       self.insert_cont()
-
-# Transport Layer model
-def print_transport(s):
-       print_with_prefix(s, "[TRN]: ")
-
-def get_field_data(field, packet):
-       return (packet[field.dword] >> field.offset) & (2**field.width-1)
-
-class FIS:
-       def __init__(self, packet, description, direction="H2D"):
-               self.packet = packet
-               self.description = description
-               self.direction = direction
-               self.decode()
-
-       def decode(self):
-               for k, v in self.description.items():
-                       setattr(self, k, get_field_data(v, self.packet))
-
-       def encode(self):
-               for k, v in self.description.items():
-                       self.packet[v.dword] |= (getattr(self, k) << v.offset)
-
-       def __repr__(self):
-               if self.direction == "H2D":
-                       r = ">>>>>>>>\n"
-               else:
-                       r = "<<<<<<<<\n"
-               for k in sorted(self.description.keys()):
-                       r += k + " : 0x%x" %getattr(self,k) + "\n"
-               return r
-
-class FIS_REG_H2D(FIS):
-       def __init__(self, packet=[0]*fis_reg_h2d_cmd_len):
-               FIS.__init__(self, packet, fis_reg_h2d_layout)
-               self.type = fis_types["REG_H2D"]
-               self.direction = "H2D"
-
-       def __repr__(self):
-               r = "FIS_REG_H2D\n"
-               r += FIS.__repr__(self)
-               return r
-
-class FIS_REG_D2H(FIS):
-       def __init__(self, packet=[0]*fis_reg_d2h_cmd_len):
-               FIS.__init__(self, packet, fis_reg_d2h_layout)
-               self.type = fis_types["REG_D2H"]
-               self.direction = "D2H"
-
-       def __repr__(self):
-               r = "FIS_REG_D2H\n"
-               r += FIS.__repr__(self)
-               return r
-
-class FIS_DMA_ACTIVATE_D2H(FIS):
-       def __init__(self, packet=[0]*fis_dma_activate_d2h_cmd_len):
-               FIS.__init__(self, packet, fis_dma_activate_d2h_layout)
-               self.type = fis_types["DMA_ACTIVATE_D2H"]
-               self.direction = "D2H"
-
-       def __repr__(self):
-               r = "FIS_DMA_ACTIVATE_D2H\n"
-               r += FIS.__repr__(self)
-               return r
-
-class FIS_DATA(FIS):
-       def __init__(self, packet=[0], direction="H2D"):
-               FIS.__init__(self, packet, fis_data_layout, direction)
-               self.type = fis_types["DATA"]
-
-       def __repr__(self):
-               r = "FIS_DATA\n"
-               r += FIS.__repr__(self)
-               for data in self.packet[1:]:
-                       r += "%08x\n" %data
-               return r
-
-class FIS_UNKNOWN(FIS):
-       def __init__(self, packet=[0], direction="H2D"):
-               FIS.__init__(self, packet, {}, direction)
-
-       def __repr__(self):
-               r = "UNKNOWN\n"
-               if self.direction == "H2D":
-                       r += ">>>>>>>>\n"
-               else:
-                       r += "<<<<<<<<\n"
-               for dword in self.packet:
-                       r += "%08x\n" %dword
-               return r
-
-class TransportLayer(Module):
-       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 set_command_callback(self, callback):
-               self.command_callback = callback
-
-       def send(self, fis):
-               fis.encode()
-               packet = LinkTXPacket(fis.packet)
-               self.link.tx_packets.append(packet)
-               if self.debug and not self.loopback:
-                       print_transport(fis)
-
-       def callback(self, packet):
-               fis_type = packet[0] & 0xff
-               if fis_type == fis_types["REG_H2D"]:
-                       fis = FIS_REG_H2D(packet)
-               elif fis_type == fis_types["REG_D2H"]:
-                       fis = FIS_REG_D2H(packet)
-               elif fis_type == fis_types["DMA_ACTIVATE_D2H"]:
-                       fis = FIS_DMA_ACTIVATE_D2H(packet)
-               elif fis_type == fis_types["DATA"]:
-                       fis = FIS_DATA(packet, direction="H2D")
-               else:
-                       fis = FIS_UNKNOWN(packet, direction="H2D")
-               if self.debug:
-                       print_transport(fis)
-               if self.loopback:
-                       self.send(fis)
-               else:
-                       self.command_callback(fis)
-
-# Command Layer model
-class CommandLayer(Module):
-       def __init__(self, transport):
-               self.transport = transport
-               self.transport.set_command_callback(self.callback)
-
-               self.hdd = None
-
-       def set_hdd(self, hdd):
-               self.hdd = hdd
-
-       def callback(self, fis):
-               resp = None
-               if isinstance(fis, FIS_REG_H2D):
-                       if fis.command == regs["WRITE_DMA_EXT"]:
-                               resp =  self.hdd.write_dma_callback(fis)
-                       elif fis.command == regs["READ_DMA_EXT"]:
-                               resp = self.hdd.read_dma_callback(fis)
-               elif isinstance(fis, FIS_DATA):
-                       resp = self.hdd.data_callback(fis)
-
-               if resp is not None:
-                       for packet in resp:
-                               self.transport.send(packet)
-
-# HDD model
-def print_hdd(s):
-       print_with_prefix(s, "[HDD]: ")
-
-class HDDMemRegion:
-       def __init__(self, base, count, sector_size):
-               self.base = base
-               self.count = count
-               self.data = [0]*(count*sector_size//4)
-
-class HDD(Module):
-       def __init__(self,
-                       link_debug=False, link_random_level=0,
-                       transport_debug=False, transport_loopback=False,
-                       hdd_debug=False,
-                       ):
-               ###
-               self.phy = PHYLayer()
-               self.link = LinkLayer(self.phy, link_debug, link_random_level)
-               self.transport = TransportLayer(self.link, transport_debug, transport_loopback)
-               self.command = CommandLayer(self.transport)
-
-               self.command.set_hdd(self)
-
-               self.debug = hdd_debug
-               self.mem = None
-               self.wr_sector = 0
-               self.wr_end_sector = 0
-               self.rd_sector = 0
-               self.rx_end_sector = 0
-
-       def malloc(self, sector, count):
-               if self.debug:
-                       s = "Allocating {n} sectors: {s} to {e}".format(n=count, s=sector, e=sector+count)
-                       s += " ({} KB)".format(count*logical_sector_size//1024)
-                       print_hdd(s)
-               self.mem = HDDMemRegion(sector, count, logical_sector_size)
-
-       def write(self, sector, data):
-               n = math.ceil(dwords2sectors(len(data)))
-               if self.debug:
-                       if n == 1:
-                               s = "{}".format(sector)
-                       else:
-                               s = "{s} to {e}".format(s=sector, e=sector+n-1)
-                       print_hdd("Writing sector " + s)
-               for i in range(len(data)):
-                       offset = sectors2dwords(sector)
-                       self.mem.data[offset+i] = data[i]
-
-       def read(self, sector, count):
-               if self.debug:
-                       if count == 1:
-                               s = "{}".format(sector)
-                       else:
-                               s = "{s} to {e}".format(s=sector, e=sector+count-1)
-                       print_hdd("Reading sector " + s)
-               data = []
-               for i in range(sectors2dwords(count)):
-                       data.append(self.mem.data[sectors2dwords(sector)+i])
-               return data
-
-       def write_dma_callback(self, fis):
-               self.wr_sector = fis.lba_lsb + (fis.lba_msb << 32)
-               self.wr_end_sector = self.wr_sector + fis.count
-               return [FIS_DMA_ACTIVATE_D2H()]
-
-       def read_dma_callback(self, fis):
-               self.rd_sector = fis.lba_lsb + (fis.lba_msb << 32)
-               self.rd_end_sector = self.rd_sector + fis.count
-               packets = []
-               while self.rd_sector != self.rd_end_sector:
-                       count = min(self.rd_end_sector-self.rd_sector, (fis_max_dwords*4)//logical_sector_size)
-                       packet = self.read(self.rd_sector, count)
-                       packet.insert(0, 0)
-                       packets.append(FIS_DATA(packet, direction="D2H"))
-                       self.rd_sector += count
-               packets.append(FIS_REG_D2H())
-               return packets
-
-       def data_callback(self, fis):
-               self.write(self.wr_sector, fis.packet[1:])
-               self.wr_sector += dwords2sectors(len(fis.packet[1:]))
-               if self.wr_sector == self.wr_end_sector:
-                       return [FIS_REG_D2H()]
-               else:
-                       return [FIS_DMA_ACTIVATE_D2H()]
diff --git a/lib/sata/test/link_tb.py b/lib/sata/test/link_tb.py
deleted file mode 100644 (file)
index 4c8e689..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-from lib.sata.common import *
-from lib.sata.link import SATALink
-
-from lib.sata.test.common import *
-from lib.sata.test.hdd import *
-
-class LinkStreamer(PacketStreamer):
-       def __init__(self):
-               PacketStreamer.__init__(self, link_description(32), LinkTXPacket)
-
-class LinkLogger(PacketLogger):
-       def __init__(self):
-               PacketLogger.__init__(self, link_description(32), LinkRXPacket)
-
-class TB(Module):
-       def __init__(self):
-               self.hdd = HDD(
-                               link_debug=False, link_random_level=50,
-                               transport_debug=False, transport_loopback=True)
-               self.link = InsertReset(SATALink(self.hdd.phy))
-
-               self.streamer = LinkStreamer()
-               self.streamer_randomizer = Randomizer(link_description(32), level=50)
-
-               self.logger_randomizer = Randomizer(link_description(32), level=50)
-               self.logger = LinkLogger()
-
-               self.pipeline = Pipeline(
-                       self.streamer,
-                       self.streamer_randomizer,
-                       self.link,
-                       self.logger_randomizer,
-                       self.logger
-               )
-
-       def gen_simulation(self, selfp):
-               for i in range(8):
-                       streamer_packet = LinkTXPacket([i for i in range(64)])
-                       yield from self.streamer.send(streamer_packet)
-                       yield from self.logger.receive()
-
-                       # 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=2048, vcd_name="my.vcd", keep_files=True)
diff --git a/lib/sata/test/phy_datapath_tb.py b/lib/sata/test/phy_datapath_tb.py
deleted file mode 100644 (file)
index d91092f..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-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.cd_sata_rx = ClockDomain()
-               self.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=10)
-               self.trx = TRX()
-               self.ctrl = CTRL()
-               self.datapath = SATAPHYDatapath(self.trx, self.ctrl)
-               self.logger_randomizer = Randomizer(phy_description(32), level=10)
-               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)
diff --git a/lib/sata/test/scrambler.c b/lib/sata/test/scrambler.c
deleted file mode 100644 (file)
index cee4b30..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-// Adapted from SATA specification
-/****************************************************************************/
-/*                                                                          */
-/* scramble.c                                                               */
-/*                                                                          */
-/* This sample code generates the entire sequence of 65535 Dwords produced  */
-/* by the scrambler defined in the Serial ATA specification. The            */
-/* specification calls for an LFSR to generate a string of bits that will   */
-/* be packaged into 32 bit Dwords to be XORed with the data Dwords. The     */
-/* generator polynomial specified is:                                       */
-/*         16  15  13  4                                                    */
-/* G(x) = x + x + x + x + 1                                                 */
-/*                                                                          */
-/* Parallelized versions of the scrambler are initialized to a value        */
-/* derived from the initialization value of 0xFFFF defined in the           */
-/* specification. This implementation is initialized to 0xF0F6. Other       */
-/* parallel implementations will have different initial values. The         */
-/* important point is that the first Dword output of any implementation     */
-/* must equal 0xC2D2768D.                                                   */
-/* This code does not represent an elegant solution for a C implementation, */
-/* but it does demonstrate a method of generating the sequence that can be  */
-/* easily implemented in hardware. A block diagram of the circuit emulated  */
-/* by this code is shown below.                                             */
-/*                                                                          */
-/* +-----------------------------------+                                    */
-/* |                                   |                                    */
-/* |                                   |                                    */
-/* |     +---+                +---+    |                                    */
-/* |     | R |                | * |    |                                    */
-/* +---->| e |----------+---->| M |----+----> Output(31 downto 16)          */
-/*       | g |          |     | 1 |                                         */
-/*       +---+          |     +---+                                         */
-/*                      |                                                   */
-/*                      |     +---+                                         */
-/*                      |     | * |                                         */
-/*                      +---->| M |---------> Output(15 downto 0)           */
-/*                            | 2 |                                         */
-/*                            +---+                                         */
-/*                                                                          */
-/* The register shown in the block diagram is a 16 bit register. The two    */
-/* boxes, *M1 and *M2, each represent a multiply by a 16 by 16 binary       */
-/* matrix. A 16 by 16 matrix times a 16 bit vector yields a 16 bit vector.  */
-/* The two vectors are the two halves of the 32 bit scrambler value. The    */
-/* upper half of the scrambler value is stored back into the context        */
-/* register to be used to generate the next value in the scrambler          */
-/*                                                                          */
-/****************************************************************************/
-#include <stdlib.h>
-#include <stdio.h>
-int main(int argc, char *argv[])
-{
-   int               i, j;
-   unsigned int      length;
-   unsigned short    context;
-   unsigned long     scrambler;
-   unsigned char     now[16];
-   unsigned char     next[32];
-   context = 0xF0F6;
-
-   scanf("0x%8x", &length);
-
-   for (i = 0; i < length; ++i)  {
-      for (j = 0; j < 16; ++j)  {
-         now[j] = (context >> j) & 0x01;
-      }
-      next[31] = now[12] ^ now[10] ^ now[7]  ^ now[3]  ^ now[1]  ^ now[0];
-      next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9]  ^ now[6]  ^ now[3]  ^ now[2]  ^ now[0];
-      next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8]  ^ now[5]  ^ now[3]  ^ now[2]  ^ now[1];
-      next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9]  ^ now[7]  ^ now[4]  ^ now[2]  ^ now[1]  ^ now[0];
-      next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9]  ^ now[8]  ^ now[6]  ^ now[1]  ^ now[0];
-      next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[5]  ^ now[3]  ^ now[0];
-      next[25] = now[15] ^ now[10] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[6]  ^ now[4]  ^ now[3]  ^ now[2];
-      next[24] = now[14] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[6]  ^ now[5]  ^ now[3]  ^ now[2]  ^ now[1];
-      next[23] = now[13] ^ now[8]  ^ now[7]  ^ now[6]  ^ now[5]  ^ now[4]  ^ now[2]  ^ now[1]  ^ now[0];
-      next[22] = now[15] ^ now[14] ^ now[7]  ^ now[6]  ^ now[5]  ^ now[4]  ^ now[1]  ^ now[0];
-      next[21] = now[15] ^ now[13] ^ now[12] ^ now[6]  ^ now[5]  ^ now[4]  ^ now[0];
-      next[20] = now[15] ^ now[11] ^ now[5]  ^ now[4];
-      next[19] = now[14] ^ now[10] ^ now[4]  ^ now[3];
-      next[18] = now[13] ^ now[9]  ^ now[3]  ^ now[2];
-      next[17] = now[12] ^ now[8]  ^ now[2]  ^ now[1];
-      next[16] = now[11] ^ now[7]  ^ now[1]  ^ now[0];
-
-
-      next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6]  ^ now[3]  ^ now[0];
-      next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9]  ^ now[5]  ^ now[3]  ^ now[2];
-      next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8]  ^ now[4]  ^ now[2]  ^ now[1];
-      next[12] = now[13] ^ now[11] ^ now[10] ^ now[9]  ^ now[7]  ^ now[3]  ^ now[1]  ^ now[0];
-      next[11] = now[15] ^ now[14] ^ now[10] ^ now[9]  ^ now[8]  ^ now[6]  ^ now[3]  ^ now[2]  ^ now[0];
-      next[10] = now[15] ^ now[13] ^ now[12] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[5]  ^ now[3]  ^ now[2]  ^ now[1];
-      next[9]  = now[14] ^ now[12] ^ now[11] ^ now[8]  ^ now[7]  ^ now[6]  ^ now[4]  ^ now[2]  ^ now[1]  ^ now[0];
-      next[8]  = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7]  ^ now[6]  ^ now[5]  ^ now[1]  ^ now[0];
-      next[7]  = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9]  ^ now[6]  ^ now[5]  ^ now[4]  ^ now[3]  ^ now[0];
-      next[6]  = now[15] ^ now[10] ^ now[9]  ^ now[8]  ^ now[5]  ^ now[4]  ^ now[2];
-      next[5]  = now[14] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[4]  ^ now[3]  ^ now[1];
-      next[4]  = now[13] ^ now[8]  ^ now[7]  ^ now[6]  ^ now[3]  ^ now[2]  ^ now[0];
-      next[3]  = now[15] ^ now[14] ^ now[7]  ^ now[6]  ^ now[5]  ^ now[3]  ^ now[2]  ^ now[1];
-      next[2]  = now[14] ^ now[13] ^ now[6]  ^ now[5]  ^ now[4]  ^ now[2]  ^ now[1]  ^ now[0];
-      next[1]  = now[15] ^ now[14] ^ now[13] ^ now[5]  ^ now[4]  ^ now[1]  ^ now[0];
-      next[0]  = now[15] ^ now[13] ^ now[4]  ^ now[0];
-
-      scrambler = 0;
-      for (j = 31; j >= 0; --j)  {
-         scrambler = scrambler << 1;
-         scrambler |= next[j];
-      }
-      context = scrambler >> 16;
-      printf("%08x\n", (unsigned int) scrambler);
-
-   }
-
-   return 0;
-
-}
\ No newline at end of file
diff --git a/lib/sata/test/scrambler_tb.py b/lib/sata/test/scrambler_tb.py
deleted file mode 100644 (file)
index 69d7b63..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-import subprocess
-
-from lib.sata.common import *
-from lib.sata.link.scrambler import *
-
-from lib.sata.test.common import *
-
-class TB(Module):
-       def __init__(self, length):
-               self.scrambler = InsertReset(Scrambler())
-               self.length = length
-
-       def get_c_values(self, length):
-               stdin = "0x%08x" %length
-               with subprocess.Popen("./scrambler", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
-                       process.stdin.write(stdin.encode("ASCII"))
-                       out, err = process.communicate()
-               return [int(e, 16) for e in out.decode("ASCII").split("\n")[:-1]]
-
-       def gen_simulation(self, selfp):
-               # init CRC
-               selfp.scrambler.ce = 1
-               selfp.scrambler.reset = 1
-               yield
-               selfp.scrambler.reset = 0
-
-               # log results
-               yield
-               sim_values = []
-               for i in range(self.length):
-                       sim_values.append(selfp.scrambler.value)
-                       yield
-
-               # stop
-               selfp.scrambler.ce = 0
-               for i in range(32):
-                       yield
-
-               # get C code reference
-               c_values = self.get_c_values(self.length)
-
-               # check results
-               s, l, e = check(c_values, sim_values)
-               print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-if __name__ == "__main__":
-       from migen.sim.generic import run_simulation
-       length = 8192
-       run_simulation(TB(length), ncycles=length+100, vcd_name="my.vcd")
diff --git a/lib/sata/transport/__init__.py b/lib/sata/transport/__init__.py
deleted file mode 100644 (file)
index 6fcb303..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-from lib.sata.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
-
-class SATATransportTX(Module):
-       def __init__(self, link):
-               self.sink = sink = Sink(transport_tx_description(32))
-
-               ###
-
-               cmd_ndwords = max(fis_reg_h2d_cmd_len, fis_data_cmd_len)
-               encoded_cmd = Signal(cmd_ndwords*32)
-
-               self.counter = counter = Counter(max=cmd_ndwords+1)
-
-               cmd_len = Signal(counter.width)
-               cmd_with_data = Signal()
-
-               cmd_send = Signal()
-               data_send = Signal()
-               cmd_done = Signal()
-
-               def test_type(name):
-                       return sink.type == fis_types[name]
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-               fsm.act("IDLE",
-                       sink.ack.eq(0),
-                       counter.reset.eq(1),
-                       If(sink.stb & sink.sop,
-                               If(test_type("REG_H2D"),
-                                       NextState("SEND_REG_H2D_CMD")
-                               ).Elif(test_type("DATA"),
-                                       NextState("SEND_DATA_CMD")
-                               ).Else(
-                                       sink.ack.eq(1)
-                               )
-                       ).Else(
-                               sink.ack.eq(1)
-                       )
-               )
-               fsm.act("SEND_REG_H2D_CMD",
-                       _encode_cmd(sink, fis_reg_h2d_layout, encoded_cmd),
-                       cmd_len.eq(fis_reg_h2d_cmd_len-1),
-                       cmd_send.eq(1),
-                       If(cmd_done,
-                               sink.ack.eq(1),
-                               NextState("IDLE")
-                       )
-               )
-               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),
-                       cmd_with_data.eq(1),
-                       cmd_send.eq(1),
-                       If(cmd_done,
-                               NextState("SEND_DATA")
-                       )
-               )
-               fsm.act("SEND_DATA",
-                       data_send.eq(1),
-                       sink.ack.eq(link.sink.ack),
-                       If(sink.stb & sink.eop & sink.ack,
-                               NextState("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(sink.stb),
-                               link.sink.sop.eq(counter.value == 0),
-                               link.sink.eop.eq((counter.value == cmd_len) & ~cmd_with_data),
-                               Case(counter.value, cmd_cases),
-                               counter.ce.eq(sink.stb & link.sink.ack),
-                               cmd_done.eq((counter.value == cmd_len) & link.sink.stb & link.sink.ack)
-                       ).Elif(data_send,
-                               link.sink.stb.eq(sink.stb),
-                               link.sink.sop.eq(0),
-                               link.sink.eop.eq(sink.eop),
-                               link.sink.d.eq(sink.data),
-                       )
-
-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 SATATransportRX(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_data_cmd_len)
-               encoded_cmd = Signal(cmd_ndwords*32)
-
-               self.counter = counter = Counter(max=cmd_ndwords+1)
-
-               cmd_len = Signal(counter.width)
-
-               cmd_receive = Signal()
-               data_receive = Signal()
-               cmd_done = Signal()
-               data_done = Signal()
-
-               def test_type(name):
-                       return link.source.d[:8] == fis_types[name]
-
-               self.fsm = fsm = FSM(reset_state="IDLE")
-
-               data_sop = Signal()
-
-               fsm.act("IDLE",
-                       link.source.ack.eq(0),
-                       counter.reset.eq(1),
-                       If(link.source.stb & link.source.sop,
-                               If(test_type("REG_D2H"),
-                                       NextState("RECEIVE_REG_D2H_CMD")
-                               ).Elif(test_type("DMA_ACTIVATE_D2H"),
-                                       NextState("RECEIVE_DMA_ACTIVATE_D2H_CMD")
-                               ).Elif(test_type("PIO_SETUP_D2H"),
-                                       NextState("RECEIVE_PIO_SETUP_D2H_CMD")
-                               ).Elif(test_type("DATA"),
-                                       NextState("RECEIVE_DATA_CMD"),
-                               ).Else(
-                                       link.source.ack.eq(1)
-                               )
-                       ).Else(
-                               link.source.ack.eq(1)
-                       )
-               )
-               fsm.act("RECEIVE_REG_D2H_CMD",
-                       cmd_len.eq(fis_reg_d2h_cmd_len-1),
-                       cmd_receive.eq(1),
-                       link.source.ack.eq(1),
-                       If(cmd_done,
-                               NextState("PRESENT_REG_D2H_CMD")
-                       )
-               )
-               fsm.act("PRESENT_REG_D2H_CMD",
-                       source.stb.eq(1),
-                       source.sop.eq(1),
-                       source.eop.eq(1),
-                       _decode_cmd(encoded_cmd, fis_reg_d2h_layout, source),
-                       If(source.stb & source.ack,
-                               NextState("IDLE")
-                       )
-               )
-               fsm.act("RECEIVE_DMA_ACTIVATE_D2H_CMD",
-                       cmd_len.eq(fis_dma_activate_d2h_cmd_len-1),
-                       cmd_receive.eq(1),
-                       link.source.ack.eq(1),
-                       If(cmd_done,
-                               NextState("PRESENT_DMA_ACTIVATE_D2H_CMD")
-                       )
-               )
-               fsm.act("PRESENT_DMA_ACTIVATE_D2H_CMD",
-                       source.stb.eq(1),
-                       source.sop.eq(1),
-                       source.eop.eq(1),
-                       _decode_cmd(encoded_cmd, fis_dma_activate_d2h_layout, source),
-                       If(source.stb & source.ack,
-                               NextState("IDLE")
-                       )
-               )
-               fsm.act("RECEIVE_PIO_SETUP_D2H_CMD",
-                       cmd_len.eq(fis_pio_setup_d2h_cmd_len-1),
-                       cmd_receive.eq(1),
-                       link.source.ack.eq(1),
-                       If(cmd_done,
-                               NextState("PRESENT_PIO_SETUP_D2H_CMD")
-                       )
-               )
-               fsm.act("PRESENT_PIO_SETUP_D2H_CMD",
-                       source.stb.eq(1),
-                       source.sop.eq(1),
-                       source.eop.eq(1),
-                       _decode_cmd(encoded_cmd, fis_pio_setup_d2h_layout, source),
-                       If(source.stb & source.ack,
-                               NextState("IDLE")
-                       )
-               )
-               fsm.act("RECEIVE_DATA_CMD",
-                       cmd_len.eq(fis_data_cmd_len-1),
-                       cmd_receive.eq(1),
-                       link.source.ack.eq(1),
-                       If(cmd_done,
-                               NextState("PRESENT_DATA")
-                       )
-               )
-               fsm.act("PRESENT_DATA",
-                       data_receive.eq(1),
-                       source.stb.eq(link.source.stb),
-                       _decode_cmd(encoded_cmd, fis_data_layout, source),
-                       source.sop.eq(data_sop),
-                       source.eop.eq(link.source.eop),
-                       source.error.eq(link.source.error),
-                       source.data.eq(link.source.d),
-                       link.source.ack.eq(source.ack),
-                       If(source.stb & source.eop & source.ack,
-                               NextState("IDLE")
-                       )
-               )
-
-               self.sync += \
-                       If(fsm.ongoing("RECEIVE_DATA_CMD"),
-                               data_sop.eq(1)
-                       ).Elif(fsm.ongoing("PRESENT_DATA"),
-                               If(source.stb & source.ack,
-                                       data_sop.eq(0)
-                               )
-                       )
-
-               cmd_cases = {}
-               for i in range(cmd_ndwords):
-                       cmd_cases[i] = [encoded_cmd[32*i:32*(i+1)].eq(link.source.d)]
-
-               self.comb += \
-                       If(cmd_receive & link.source.stb,
-                               counter.ce.eq(1)
-                       )
-               self.sync += \
-                       If(cmd_receive,
-                               Case(counter.value, cmd_cases),
-                       )
-               self.comb += cmd_done.eq((counter.value == cmd_len) & link.source.ack)
-
-class SATATransport(Module):
-       def __init__(self, link):
-               self.tx = SATATransportTX(link)
-               self.rx = SATATransportRX(link)
-               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/litesata/__init__.py b/litesata/__init__.py
new file mode 100644 (file)
index 0000000..c75fc32
--- /dev/null
@@ -0,0 +1,23 @@
+from litesata.common import *
+from litesata.phy import *
+from litesata.core import *
+from litesata.frontend import *
+
+from migen.bank.description import *
+
+class LiteSATA(Module, AutoCSR):
+       def __init__(self, phy,
+                       with_crossbar=False,
+                       with_bist=False, with_bist_csr=False):
+               # phy
+               self.phy = phy
+
+               # core
+               self.core = LiteSATACore(self.phy)
+
+               # frontend
+               if with_crossbar:
+                       self.crossbar = LiteSATACrossbar(self.core)
+               if with_bist:
+                       self.bist = LiteSATABIST(self.crossbar, with_bist_csr)
+
diff --git a/litesata/common.py b/litesata/common.py
new file mode 100644 (file)
index 0000000..99c5d21
--- /dev/null
@@ -0,0 +1,287 @@
+import math
+
+from migen.fhdl.std import *
+from migen.genlib.resetsync import *
+from migen.genlib.fsm import *
+from migen.genlib.record import *
+from migen.genlib.misc import chooser, optree
+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
+
+# PHY / Link Layers
+primitives = {
+       "ALIGN" :       0x7B4A4ABC,
+       "CONT"  :       0X9999AA7C,
+       "SYNC"  :       0xB5B5957C,
+       "R_RDY" :       0x4A4A957C,
+       "R_OK"  :       0x3535B57C,
+       "R_ERR" :       0x5656B57C,
+       "R_IP"  :       0X5555B57C,
+       "X_RDY" :       0x5757B57C,
+       "CONT"  :       0x9999AA7C,
+       "WTRM"  :       0x5858B57C,
+       "SOF"   :       0x3737B57C,
+       "EOF"   :       0xD5D5B57C,
+       "HOLD"  :       0xD5D5AA7C,
+       "HOLDA" :       0X9595AA7C
+}
+
+def is_primitive(dword):
+       for k, v in primitives.items():
+               if dword == v:
+                       return True
+       return False
+
+def decode_primitive(dword):
+       for k, v in primitives.items():
+               if dword == v:
+                       return k
+       return ""
+
+def phy_description(dw):
+       layout = [
+               ("data", dw),
+               ("charisk", dw//8),
+       ]
+       return EndpointDescription(layout, packetized=False)
+
+def link_description(dw):
+       layout = [
+               ("d", dw),
+               ("error", 1)
+       ]
+       return EndpointDescription(layout, packetized=True)
+
+# Transport Layer
+fis_max_dwords = 2048
+
+fis_types = {
+       "REG_H2D":          0x27,
+       "REG_D2H":          0x34,
+       "DMA_ACTIVATE_D2H": 0x39,
+       "PIO_SETUP_D2H":        0x5F,
+       "DATA":             0x46
+}
+
+class FISField():
+       def __init__(self, dword, offset, width):
+               self.dword = dword
+               self.offset = offset
+               self.width = width
+
+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_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)
+}
+
+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),
+
+       "lba_lsb": FISField(1, 0, 24),
+       "device":  FISField(1, 24, 8),
+
+       "lba_msb": FISField(2, 0, 24),
+
+       "count":   FISField(3, 0, 16)
+}
+
+fis_dma_activate_d2h_cmd_len = 1
+fis_dma_activate_d2h_layout = {
+       "type":    FISField(0,  0, 8),
+       "pm_port": FISField(0,  8, 4)
+}
+
+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),
+
+       "lba_lsb": FISField(1, 0, 24),
+
+       "lba_msb": FISField(2, 0, 24),
+
+       "count":   FISField(3, 0, 16),
+
+       "transfer_count":       FISField(4, 0, 16),
+}
+
+fis_data_cmd_len = 1
+fis_data_layout = {
+       "type": FISField(0,  0, 8)
+}
+
+def transport_tx_description(dw):
+       layout = [
+               ("type", 8),
+               ("pm_port", 4),
+               ("c", 1),
+               ("command", 8),
+               ("features", 16),
+               ("lba", 48),
+               ("device", 8),
+               ("count", 16),
+               ("icc", 8),
+               ("control", 8),
+               ("data", dw)
+       ]
+       return EndpointDescription(layout, packetized=True)
+
+def transport_rx_description(dw):
+       layout = [
+               ("type", 8),
+               ("pm_port", 4),
+               ("r", 1),
+               ("d", 1),
+               ("i", 1),
+               ("status", 8),
+               ("error", 8),
+               ("lba", 48),
+               ("device", 8),
+               ("count", 16),
+               ("transfer_count", 16),
+               ("data", dw),
+               ("error", 1)
+       ]
+       return EndpointDescription(layout, packetized=True)
+
+# Command Layer
+regs = {
+       "WRITE_DMA_EXT"                 : 0x35,
+       "READ_DMA_EXT"                  : 0x25,
+       "IDENTIFY_DEVICE"               : 0xEC
+}
+
+def command_tx_description(dw):
+       layout = [
+               ("write", 1),
+               ("read", 1),
+               ("identify", 1),
+               ("sector", 48),
+               ("count", 16),
+               ("data", dw)
+       ]
+       return EndpointDescription(layout, packetized=True)
+
+def command_rx_description(dw):
+       layout = [
+               ("write", 1),
+               ("read", 1),
+               ("identify", 1),
+               ("last", 1),
+               ("success", 1),
+               ("failed", 1),
+               ("data", dw)
+       ]
+       return EndpointDescription(layout, packetized=True)
+
+def command_rx_cmd_description(dw):
+       layout = [
+               ("write", 1),
+               ("read", 1),
+               ("identify", 1),
+               ("last", 1),
+               ("success", 1),
+               ("failed", 1)
+       ]
+       return EndpointDescription(layout, packetized=False)
+
+def command_rx_data_description(dw):
+       layout = [
+               ("data", dw)
+       ]
+       return EndpointDescription(layout, packetized=True)
+
+# HDD
+logical_sector_size = 512 # constant since all HDDs use this
+
+def dwords2sectors(n):
+       return math.ceil(n*4/logical_sector_size)
+
+def sectors2dwords(n):
+       return n*logical_sector_size//4
+
+# Generic modules
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class Counter(Module):
+       def __init__(self, signal=None, **kwargs):
+               if signal is None:
+                       self.value = Signal(**kwargs)
+               else:
+                       self.value = signal
+               self.width = flen(self.value)
+               self.sync += self.value.eq(self.value+1)
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class Timeout(Module):
+       def __init__(self, length):
+               self.reached = Signal()
+               ###
+               value = Signal(max=length)
+               self.sync += value.eq(value+1)
+               self.comb += [
+                       self.reached.eq(value == length)
+               ]
+
+# XXX use ModuleDecorator
+class BufferizeEndpoints(Module):
+       def __init__(self, decorated, *args):
+               self.decorated = decorated
+
+               endpoints = get_endpoints(decorated)
+               sinks = {}
+               sources = {}
+               for name, endpoint in endpoints.items():
+                       if name in args or len(args) == 0:
+                               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)
+                       self.submodules += buf
+                       setattr(self, name, buf.d)
+                       self.comb += Record.connect(buf.q, sink)
+
+               # add buffer on sources
+               for name, source in sources.items():
+                       buf = Buffer(source.description)
+                       self.submodules += buf
+                       self.comb += Record.connect(source, buf.d)
+                       setattr(self, name, buf.q)
+
+       def __getattr__(self, name):
+               return getattr(self.decorated, name)
+
+       def __dir__(self):
+               return dir(self.decorated)
diff --git a/litesata/core/__init__.py b/litesata/core/__init__.py
new file mode 100644 (file)
index 0000000..c32028b
--- /dev/null
@@ -0,0 +1,11 @@
+from litesata.common import *
+from litesata.core.link import LiteSATALink
+from litesata.core.transport import LiteSATATransport
+from litesata.core.command import LiteSATACommand
+
+class LiteSATACore(Module):
+       def __init__(self, phy):
+               self.link = LiteSATALink(phy)
+               self.transport = LiteSATATransport(self.link)
+               self.command = LiteSATACommand(self.transport)
+               self.sink, self.source = self.command.sink, self.command.source
diff --git a/litesata/core/command/__init__.py b/litesata/core/command/__init__.py
new file mode 100644 (file)
index 0000000..130b5fc
--- /dev/null
@@ -0,0 +1,314 @@
+from litesata.common import *
+
+tx_to_rx = [
+       ("write", 1),
+       ("read", 1),
+       ("identify", 1),
+       ("count", 16)
+]
+
+rx_to_tx = [
+       ("dma_activate", 1)
+]
+
+class LiteSATACommandTX(Module):
+       def __init__(self, transport):
+               self.sink = sink = Sink(command_tx_description(32))
+               self.to_rx = to_rx = Source(tx_to_rx)
+               self.from_rx = from_rx = Sink(rx_to_tx)
+
+               ###
+
+               self.comb += [
+                       transport.sink.pm_port.eq(0),
+                       transport.sink.features.eq(0),
+                       transport.sink.lba.eq(sink.sector),
+                       transport.sink.device.eq(0xe0),
+                       transport.sink.count.eq(sink.count),
+                       transport.sink.icc.eq(0),
+                       transport.sink.control.eq(0),
+                       transport.sink.data.eq(sink.data)
+               ]
+
+               self.dwords_counter = dwords_counter = Counter(max=fis_max_dwords)
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+               fsm.act("IDLE",
+                       sink.ack.eq(0),
+                       If(sink.stb & sink.sop,
+                               If(sink.write,
+                                       NextState("SEND_WRITE_DMA_CMD")
+                               ).Elif(sink.read,
+                                       NextState("SEND_READ_DMA_CMD")
+                               ).Elif(sink.identify,
+                                       NextState("SEND_IDENTIFY_CMD")
+                               ).Else(
+                                       sink.ack.eq(1)
+                               )
+                       ).Else(
+                               sink.ack.eq(1)
+                       )
+               )
+               fsm.act("SEND_WRITE_DMA_CMD",
+                       transport.sink.stb.eq(sink.stb),
+                       transport.sink.sop.eq(1),
+                       transport.sink.eop.eq(1),
+                       transport.sink.type.eq(fis_types["REG_H2D"]),
+                       transport.sink.c.eq(1),
+                       transport.sink.command.eq(regs["WRITE_DMA_EXT"]),
+                       If(sink.stb & transport.sink.ack,
+                               NextState("WAIT_DMA_ACTIVATE")
+                       )
+               )
+               fsm.act("WAIT_DMA_ACTIVATE",
+                       dwords_counter.reset.eq(1),
+                       If(from_rx.dma_activate,
+                               NextState("SEND_DATA")
+                       )
+               )
+               fsm.act("SEND_DATA",
+                       dwords_counter.ce.eq(sink.stb & sink.ack),
+
+                       transport.sink.stb.eq(sink.stb),
+                       transport.sink.sop.eq(dwords_counter.value == 0),
+                       transport.sink.eop.eq((dwords_counter.value == (fis_max_dwords-1)) | sink.eop),
+
+                       transport.sink.type.eq(fis_types["DATA"]),
+                       sink.ack.eq(transport.sink.ack),
+                       If(sink.stb & sink.ack,
+                               If(sink.eop,
+                                       NextState("IDLE")
+                               ).Elif(dwords_counter.value == (fis_max_dwords-1),
+                                       NextState("WAIT_DMA_ACTIVATE")
+                               )
+                       )
+               )
+               fsm.act("SEND_READ_DMA_CMD",
+                       transport.sink.stb.eq(sink.stb),
+                       transport.sink.sop.eq(1),
+                       transport.sink.eop.eq(1),
+                       transport.sink.type.eq(fis_types["REG_H2D"]),
+                       transport.sink.c.eq(1),
+                       transport.sink.command.eq(regs["READ_DMA_EXT"]),
+                       sink.ack.eq(transport.sink.ack),
+                       If(sink.stb & sink.ack,
+                               NextState("IDLE")
+                       )
+               )
+               fsm.act("SEND_IDENTIFY_CMD",
+                       transport.sink.stb.eq(sink.stb),
+                       transport.sink.sop.eq(1),
+                       transport.sink.eop.eq(1),
+                       transport.sink.type.eq(fis_types["REG_H2D"]),
+                       transport.sink.c.eq(1),
+                       transport.sink.command.eq(regs["IDENTIFY_DEVICE"]),
+                       sink.ack.eq(transport.sink.ack),
+                       If(sink.stb & sink.ack,
+                               NextState("IDLE")
+                       )
+               )
+
+               self.comb += [
+                       If(sink.stb,
+                               to_rx.write.eq(sink.write),
+                               to_rx.read.eq(sink.read),
+                               to_rx.identify.eq(sink.identify),
+                               to_rx.count.eq(sink.count)
+                       )
+               ]
+
+class LiteSATACommandRX(Module):
+       def __init__(self, transport):
+               self.source = source = Source(command_rx_description(32))
+               self.to_tx = to_tx = Source(rx_to_tx)
+               self.from_tx = from_tx = Sink(tx_to_rx)
+
+               ###
+
+               cmd_buffer = Buffer(command_rx_cmd_description(32))
+               cmd_buffer.sink, cmd_buffer.source = cmd_buffer.d, cmd_buffer.q
+               data_buffer = InsertReset(SyncFIFO(command_rx_data_description(32), fis_max_dwords, buffered=True))
+               self.submodules += cmd_buffer, data_buffer
+
+               def test_type(name):
+                       return transport.source.type == fis_types[name]
+
+               identify = Signal()
+               dma_activate = Signal()
+               read_ndwords = Signal(max=sectors2dwords(2**16))
+               self.dwords_counter = dwords_counter = Counter(max=sectors2dwords(2**16))
+               read_done = Signal()
+
+               self.sync += \
+                       If(from_tx.read,
+                               read_ndwords.eq(from_tx.count*sectors2dwords(1)-1)
+                       )
+               self.comb += read_done.eq(self.dwords_counter.value == read_ndwords)
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+               fsm.act("IDLE",
+                       self.dwords_counter.reset.eq(1),
+                       transport.source.ack.eq(1),
+                       If(from_tx.write,
+                               NextState("WAIT_WRITE_ACTIVATE_OR_REG_D2H")
+                       ).Elif(from_tx.read,
+                               NextState("WAIT_READ_DATA_OR_REG_D2H"),
+                       ).Elif(from_tx.identify,
+                               NextState("WAIT_PIO_SETUP_D2H"),
+                       )
+               )
+               self.sync += \
+                       If(fsm.ongoing("IDLE"),
+                               identify.eq(from_tx.identify)
+                       )
+               fsm.act("WAIT_WRITE_ACTIVATE_OR_REG_D2H",
+                       transport.source.ack.eq(1),
+                       If(transport.source.stb,
+                               If(test_type("DMA_ACTIVATE_D2H"),
+                                       dma_activate.eq(1),
+                               ).Elif(test_type("REG_D2H"),
+                                       # XXX: use status and error fields of REG_D2H
+                                       NextState("PRESENT_WRITE_RESPONSE")
+                               )
+                       )
+               )
+               fsm.act("PRESENT_WRITE_RESPONSE",
+                       cmd_buffer.sink.stb.eq(1),
+                       cmd_buffer.sink.write.eq(1),
+                       cmd_buffer.sink.last.eq(1),
+                       cmd_buffer.sink.success.eq(~transport.source.error),
+                       cmd_buffer.sink.failed.eq(transport.source.error),
+                       If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
+                               NextState("IDLE")
+                       )
+               )
+               fsm.act("WAIT_READ_DATA_OR_REG_D2H",
+                       transport.source.ack.eq(1),
+                       If(transport.source.stb,
+                               transport.source.ack.eq(0),
+                               If(test_type("DATA"),
+                                       NextState("PRESENT_READ_DATA")
+                               ).Elif(test_type("REG_D2H"),
+                                       # XXX: use status and error fields of REG_D2H
+                                       NextState("PRESENT_READ_RESPONSE")
+                               )
+                       )
+               )
+               fsm.act("WAIT_PIO_SETUP_D2H",
+                       transport.source.ack.eq(1),
+                       If(transport.source.stb,
+                               transport.source.ack.eq(0),
+                               If(test_type("PIO_SETUP_D2H"),
+                                       NextState("PRESENT_PIO_SETUP_D2H")
+                               )
+                       )
+               )
+               fsm.act("PRESENT_PIO_SETUP_D2H",
+                       transport.source.ack.eq(1),
+                       # XXX : Check error/ status
+                       If(transport.source.stb & transport.source.eop,
+                               NextState("WAIT_READ_DATA_OR_REG_D2H")
+                       )
+               )
+
+               self.comb += [
+                       data_buffer.sink.sop.eq(transport.source.sop),
+                       data_buffer.sink.eop.eq(transport.source.eop),
+                       data_buffer.sink.data.eq(transport.source.data)
+               ]
+               fsm.act("PRESENT_READ_DATA",
+                       data_buffer.sink.stb.eq(transport.source.stb),
+                       transport.source.ack.eq(data_buffer.sink.ack),
+                       If(data_buffer.sink.stb & data_buffer.sink.ack,
+                               self.dwords_counter.ce.eq(~read_done),
+                               If(data_buffer.sink.eop,
+                                       If(read_done & ~identify,
+                                               NextState("WAIT_READ_DATA_OR_REG_D2H")
+                                       ).Else(
+                                               NextState("PRESENT_READ_RESPONSE")
+                                       )
+                               )
+                       )
+               )
+               read_error = Signal()
+               self.sync += \
+                       If(fsm.before_entering("PRESENT_READ_DATA"),
+                               read_error.eq(1)
+                       ).Elif(transport.source.stb & transport.source.ack & transport.source.eop,
+                               read_error.eq(transport.source.error)
+                       )
+               fsm.act("PRESENT_READ_RESPONSE",
+                       cmd_buffer.sink.stb.eq(1),
+                       cmd_buffer.sink.read.eq(~identify),
+                       cmd_buffer.sink.identify.eq(identify),
+                       cmd_buffer.sink.last.eq(read_done | identify),
+                       cmd_buffer.sink.success.eq(~read_error),
+                       cmd_buffer.sink.failed.eq(read_error),
+                       If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
+                               If(cmd_buffer.sink.failed,
+                                       data_buffer.reset.eq(1)
+                               ),
+                               If(read_done | identify,
+                                       NextState("IDLE")
+                               ).Else(
+                                       NextState("WAIT_READ_DATA_OR_REG_D2H")
+                               )
+                       )
+               )
+
+               self.out_fsm = out_fsm = FSM(reset_state="IDLE")
+               out_fsm.act("IDLE",
+                       If(cmd_buffer.source.stb,
+                               If((cmd_buffer.source.read | cmd_buffer.source.identify) & cmd_buffer.source.success,
+                                       NextState("PRESENT_RESPONSE_WITH_DATA"),
+                               ).Else(
+                                       NextState("PRESENT_RESPONSE_WITHOUT_DATA"),
+                               )
+                       )
+               )
+
+               self.comb += [
+                       source.write.eq(cmd_buffer.source.write),
+                       source.read.eq(cmd_buffer.source.read),
+                       source.identify.eq(cmd_buffer.source.identify),
+                       source.last.eq(cmd_buffer.source.last),
+                       source.success.eq(cmd_buffer.source.success),
+                       source.failed.eq(cmd_buffer.source.failed),
+                       source.data.eq(data_buffer.source.data)
+               ]
+
+               out_fsm.act("PRESENT_RESPONSE_WITH_DATA",
+                       source.stb.eq(data_buffer.source.stb),
+                       source.sop.eq(data_buffer.source.sop),
+                       source.eop.eq(data_buffer.source.eop),
+
+                       data_buffer.source.ack.eq(source.ack),
+
+                       If(source.stb & source.eop & source.ack,
+                               cmd_buffer.source.ack.eq(1),
+                               NextState("IDLE")
+                       )
+               )
+               out_fsm.act("PRESENT_RESPONSE_WITHOUT_DATA",
+                       source.stb.eq(1),
+                       source.sop.eq(1),
+                       source.eop.eq(1),
+                       If(source.stb & source.ack,
+                               cmd_buffer.source.ack.eq(1),
+                               NextState("IDLE")
+                       )
+               )
+
+               self.comb += [
+                       to_tx.dma_activate.eq(dma_activate),
+               ]
+
+class LiteSATACommand(Module):
+       def __init__(self, transport):
+               self.tx = LiteSATACommandTX(transport)
+               self.rx = LiteSATACommandRX(transport)
+               self.comb += [
+                       self.rx.to_tx.connect(self.tx.from_rx),
+                       self.tx.to_rx.connect(self.rx.from_tx)
+               ]
+               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/litesata/core/link/__init__.py b/litesata/core/link/__init__.py
new file mode 100644 (file)
index 0000000..64884ee
--- /dev/null
@@ -0,0 +1,244 @@
+from litesata.common import *
+from litesata.core.link.crc import LiteSATACRCInserter, LiteSATACRCChecker
+from litesata.core.link.scrambler import LiteSATAScrambler
+from litesata.core.link.cont import LiteSATACONTInserter, LiteSATACONTRemover
+
+from_rx = [
+       ("idle", 1),
+       ("insert", 32),
+       ("det", 32)
+]
+
+class LiteSATALinkTX(Module):
+       def __init__(self, phy):
+               self.sink = Sink(link_description(32))
+               self.from_rx = Sink(from_rx)
+
+               ###
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+
+               # insert CRC
+               crc = LiteSATACRCInserter(link_description(32))
+               self.submodules += crc
+
+               # scramble
+               scrambler = LiteSATAScrambler(link_description(32))
+               self.submodules += scrambler
+
+               # connect CRC / scrambler
+               self.comb += [
+                       Record.connect(self.sink, crc.sink),
+                       Record.connect(crc.source, scrambler.sink)
+               ]
+
+               # inserter CONT and scrambled data between
+               # CONT and next primitive
+               self.cont  = cont = BufferizeEndpoints(LiteSATACONTInserter(phy_description(32)), "source")
+
+               # datas / primitives mux
+               insert = Signal(32)
+               self.comb += [
+                       If(self.from_rx.insert,
+                               cont.sink.stb.eq(1),
+                               cont.sink.data.eq(self.from_rx.insert),
+                               cont.sink.charisk.eq(0x0001),
+                       ).
+                       Elif(insert,
+                               cont.sink.stb.eq(1),
+                               cont.sink.data.eq(insert),
+                               cont.sink.charisk.eq(0x0001),
+                       ).Elif(fsm.ongoing("COPY"),
+                               cont.sink.stb.eq(scrambler.source.stb),
+                               cont.sink.data.eq(scrambler.source.d),
+                               scrambler.source.ack.eq(cont.sink.ack),
+                               cont.sink.charisk.eq(0)
+                       )
+               ]
+               self.comb += Record.connect(cont.source, phy.sink)
+
+               # FSM
+               fsm.act("IDLE",
+                       scrambler.reset.eq(1),
+                       If(self.from_rx.idle,
+                               insert.eq(primitives["SYNC"]),
+                               If(scrambler.source.stb & scrambler.source.sop,
+                                       If(self.from_rx.det == primitives["SYNC"],
+                                               NextState("RDY")
+                                       )
+                               )
+                       )
+               )
+               fsm.act("RDY",
+                       insert.eq(primitives["X_RDY"]),
+                       If(~self.from_rx.idle,
+                               NextState("IDLE")
+                       ).Elif(self.from_rx.det == primitives["R_RDY"],
+                               NextState("SOF")
+                       )
+               )
+               fsm.act("SOF",
+                       insert.eq(primitives["SOF"]),
+                       If(phy.sink.ack,
+                               NextState("COPY")
+                       )
+               )
+               fsm.act("COPY",
+                       If(self.from_rx.det == primitives["HOLD"],
+                               insert.eq(primitives["HOLDA"]),
+                       ).Elif(~scrambler.source.stb,
+                               insert.eq(primitives["HOLD"]),
+                       ).Elif(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
+                               NextState("EOF")
+                       )
+               )
+               fsm.act("EOF",
+                       insert.eq(primitives["EOF"]),
+                       If(phy.sink.ack,
+                               NextState("WTRM")
+                       )
+               )
+               fsm.act("WTRM",
+                       insert.eq(primitives["WTRM"]),
+                       If(self.from_rx.det == primitives["R_OK"],
+                               NextState("IDLE")
+                       ).Elif(self.from_rx.det == primitives["R_ERR"],
+                               NextState("IDLE")
+                       )
+               )
+
+class LiteSATALinkRX(Module):
+       def __init__(self, phy):
+               self.source = Source(link_description(32))
+               self.to_tx = Source(from_rx)
+
+               ###
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+
+               # CONT remover
+               self.cont = cont = BufferizeEndpoints(LiteSATACONTRemover(phy_description(32)), "source")
+               self.comb += Record.connect(phy.source, cont.sink)
+
+               # datas / primitives detection
+               insert = Signal(32)
+               det = Signal(32)
+               self.comb += \
+                       If(cont.source.stb & (cont.source.charisk == 0b0001),
+                               det.eq(cont.source.data)
+                       )
+
+               # descrambler
+               self.scrambler = scrambler = LiteSATAScrambler(link_description(32))
+
+               # check CRC
+               self.crc = crc = LiteSATACRCChecker(link_description(32))
+
+               sop = Signal()
+               eop = Signal()
+               self.sync += \
+                       If(fsm.ongoing("IDLE"),
+                               sop.eq(1),
+                       ).Elif(fsm.ongoing("COPY"),
+                               If(scrambler.sink.stb & scrambler.sink.ack,
+                                       sop.eq(0)
+                               )
+                       )
+               self.comb += eop.eq(det == primitives["EOF"])
+
+               crc_error = Signal()
+               self.sync += \
+                       If(crc.source.stb & crc.source.eop & crc.source.ack,
+                               crc_error.eq(crc.source.error)
+                       )
+
+               # small fifo to manage HOLD
+               self.fifo = SyncFIFO(link_description(32), 32)
+
+               # graph
+               self.comb += [
+                       cont.source.ack.eq(1),
+                       Record.connect(scrambler.source, crc.sink),
+                       Record.connect(crc.source, self.fifo.sink),
+                       Record.connect(self.fifo.source, self.source)
+               ]
+               cont_source_data_d = Signal(32)
+               self.sync += \
+                       If(cont.source.stb & (det == 0),
+                               scrambler.sink.d.eq(cont.source.data)
+                       )
+
+               # FSM
+               fsm.act("IDLE",
+                       scrambler.reset.eq(1),
+                       If(det == primitives["X_RDY"],
+                               NextState("RDY")
+                       )
+               )
+               fsm.act("RDY",
+                       insert.eq(primitives["R_RDY"]),
+                       If(det == primitives["SOF"],
+                               NextState("WAIT_FIRST")
+                       )
+               )
+               fsm.act("WAIT_FIRST",
+                       insert.eq(primitives["R_IP"]),
+                       If(cont.source.stb & (det == 0),
+                               NextState("COPY")
+                       )
+               )
+               self.comb += [
+                       scrambler.sink.sop.eq(sop),
+                       scrambler.sink.eop.eq(eop)
+               ]
+               fsm.act("COPY",
+                       scrambler.sink.stb.eq(cont.source.stb & ((det == 0) | eop)),
+                       insert.eq(primitives["R_IP"]),
+                       If(det == primitives["HOLD"],
+                               insert.eq(primitives["HOLDA"])
+                       ).Elif(det == primitives["EOF"],
+                               NextState("WTRM")
+                       ).Elif(self.fifo.fifo.level > 8,
+                               insert.eq(primitives["HOLD"])
+                       )
+               )
+               fsm.act("EOF",
+                       insert.eq(primitives["R_IP"]),
+                       If(det == primitives["WTRM"],
+                               NextState("WTRM")
+                       )
+               )
+               fsm.act("WTRM",
+                       insert.eq(primitives["R_IP"]),
+                       If(~crc_error,
+                               NextState("R_OK")
+                       ).Else(
+                               NextState("R_ERR")
+                       )
+               )
+               fsm.act("R_OK",
+                       insert.eq(primitives["R_OK"]),
+                       If(det == primitives["SYNC"],
+                               NextState("IDLE")
+                       )
+               )
+               fsm.act("R_ERR",
+                       insert.eq(primitives["R_ERR"]),
+                       If(det == primitives["SYNC"],
+                               NextState("IDLE")
+                       )
+               )
+
+               # to TX
+               self.comb += [
+                       self.to_tx.idle.eq(fsm.ongoing("IDLE")),
+                       self.to_tx.insert.eq(insert),
+                       self.to_tx.det.eq(det)
+               ]
+
+class LiteSATALink(Module):
+       def __init__(self, phy):
+               self.tx = LiteSATALinkTX(phy)
+               self.rx = LiteSATALinkRX(phy)
+               self.comb += Record.connect(self.rx.to_tx, self.tx.from_rx)
+               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/litesata/core/link/cont.py b/litesata/core/link/cont.py
new file mode 100644 (file)
index 0000000..dff6a28
--- /dev/null
@@ -0,0 +1,114 @@
+from litesata.common import *
+from litesata.core.link.scrambler import Scrambler
+
+class LiteSATACONTInserter(Module):
+       def __init__(self, description):
+               self.sink = sink = Sink(description)
+               self.source = source = Source(description)
+
+               ###
+
+               self.counter = counter = Counter(max=4)
+
+               is_data = Signal()
+               was_data = Signal()
+               was_hold = Signal()
+               change = Signal()
+               self.comb += is_data.eq(sink.charisk == 0)
+
+               last_data = Signal(32)
+               last_primitive = Signal(32)
+               last_charisk = Signal(4)
+               self.sync += [
+                       If(sink.stb & source.ack,
+                               last_data.eq(sink.data),
+                               last_charisk.eq(sink.charisk),
+                               If(~is_data,
+                                       last_primitive.eq(sink.data),
+                               ),
+                               was_data.eq(is_data),
+                               was_hold.eq(last_primitive == primitives["HOLD"])
+                       )
+               ]
+               self.comb += change.eq(
+                       (sink.data != last_data) |
+                       (sink.charisk != last_charisk) |
+                       is_data
+               )
+
+               # scrambler
+               self.scrambler = scrambler = InsertReset(Scrambler())
+
+               # Datapath
+               self.comb += [
+                       Record.connect(sink, source),
+                       If(sink.stb,
+                               If(~change,
+                                       counter.ce.eq(sink.ack & (counter.value !=2)),
+                                       # insert CONT
+                                       If(counter.value == 1,
+                                               source.charisk.eq(0b0001),
+                                               source.data.eq(primitives["CONT"])
+                                       # insert scrambled data for EMI
+                                       ).Elif(counter.value == 2,
+                                               scrambler.ce.eq(sink.ack),
+                                               source.charisk.eq(0b0000),
+                                               source.data.eq(scrambler.value)
+                                       )
+                               ).Else(
+                                       counter.reset.eq(source.ack),
+                                       If(counter.value == 2,
+                                               # Reinsert last primitive
+                                               If(is_data | (~is_data & was_hold),
+                                                       source.stb.eq(1),
+                                                       sink.ack.eq(0),
+                                                       source.charisk.eq(0b0001),
+                                                       source.data.eq(last_primitive)
+                                               )
+                                       )
+                               )
+                       )
+               ]
+
+class LiteSATACONTRemover(Module):
+       def __init__(self, description):
+               self.sink = sink = Sink(description)
+               self.source = source = Source(description)
+
+               ###
+
+               is_data = Signal()
+               is_cont = Signal()
+               in_cont = Signal()
+               cont_ongoing = Signal()
+
+               self.comb += [
+                       is_data.eq(sink.charisk == 0),
+                       is_cont.eq(~is_data & (sink.data == primitives["CONT"]))
+               ]
+               self.sync += \
+                       If(sink.stb & sink.ack,
+                               If(is_cont,
+                                       in_cont.eq(1)
+                               ).Elif(~is_data,
+                                       in_cont.eq(0)
+                               )
+                       )
+               self.comb += cont_ongoing.eq(is_cont | (in_cont & is_data))
+
+               # Datapath
+               last_primitive = Signal(32)
+               self.sync += [
+                       If(sink.stb & sink.ack,
+                               If(~is_data & ~is_cont,
+                                       last_primitive.eq(sink.data)
+                               )
+                       )
+               ]
+               self.comb += [
+                       Record.connect(sink, source),
+                       If(cont_ongoing,
+                               source.charisk.eq(0b0001),
+                               source.data.eq(last_primitive)
+                       )
+               ]
diff --git a/litesata/core/link/crc.py b/litesata/core/link/crc.py
new file mode 100644 (file)
index 0000000..1f5ac61
--- /dev/null
@@ -0,0 +1,114 @@
+from litesata.common import *
+
+from migen.actorlib.crc import CRCInserter, CRCChecker
+
+class CRCEngine(Module):
+       """Cyclic Redundancy Check Engine
+
+       Compute next CRC value from last CRC value and data input using
+       an optimized asynchronous LFSR.
+
+       Parameters
+       ----------
+       width : int
+               Width of the data bus and CRC.
+       polynom : int
+               Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
+
+       Attributes
+       ----------
+       d : in
+               Data input.
+       last : in
+               last CRC value.
+       next :
+               next CRC value.
+       """
+       def __init__(self, width, polynom):
+               self.d = Signal(width)
+               self.last = Signal(width)
+               self.next = Signal(width)
+
+               ###
+
+               def _optimize_eq(l):
+                       """
+                       Replace even numbers of XORs in the equation
+                       with an equivalent XOR
+                       """
+                       d = {}
+                       for e in l:
+                               if e in d:
+                                       d[e] += 1
+                               else:
+                                       d[e] = 1
+                       r = []
+                       for key, value in d.items():
+                               if value%2 != 0:
+                                       r.append(key)
+                       return r
+
+               new = Signal(32)
+               self.comb += new.eq(self.last ^ self.d)
+
+               # compute and optimize CRC's LFSR
+               curval = [[("new", i)] for i in range(width)]
+               for i in range(width):
+                       feedback = curval.pop()
+                       for j in range(width-1):
+                               if (polynom & (1<<(j+1))):
+                                       curval[j] += feedback
+                               curval[j] = _optimize_eq(curval[j])
+                       curval.insert(0, feedback)
+
+               # implement logic
+               for i in range(width):
+                       xors = []
+                       for t, n in curval[i]:
+                               if t == "new":
+                                       xors += [new[n]]
+                       self.comb += self.next[i].eq(optree("^", xors))
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class LiteSATACRC(Module):
+       """SATA CRC
+
+       Implement a SATA CRC generator/checker
+
+       Attributes
+       ----------
+       value : out
+               CRC value (used for generator).
+       error : out
+               CRC error (used for checker).
+       """
+       width = 32
+       polynom = 0x04C11DB7
+       init = 0x52325032
+       check = 0x00000000
+       def __init__(self, dw=32):
+               self.d = Signal(self.width)
+               self.value = Signal(self.width)
+               self.error = Signal()
+
+               ###
+
+               self.engine = CRCEngine(self.width, self.polynom)
+               reg_i = Signal(self.width, reset=self.init)
+               self.sync += reg_i.eq(self.engine.next)
+               self.comb += [
+                       self.engine.d.eq(self.d),
+                       self.engine.last.eq(reg_i),
+
+                       self.value.eq(reg_i),
+                       self.error.eq(self.engine.next != self.check)
+               ]
+
+class LiteSATACRCInserter(CRCInserter):
+       def __init__(self, description):
+               CRCInserter.__init__(self, LiteSATACRC, description)
+
+class LiteSATACRCChecker(CRCChecker):
+       def __init__(self, description):
+               CRCChecker.__init__(self, LiteSATACRC, description)
diff --git a/litesata/core/link/scrambler.py b/litesata/core/link/scrambler.py
new file mode 100644 (file)
index 0000000..4b5b996
--- /dev/null
@@ -0,0 +1,80 @@
+from litesata.common import *
+
+@DecorateModule(InsertCE)
+class Scrambler(Module):
+       """SATA Scrambler
+
+       Implement a SATA Scrambler
+
+       Attributes
+       ----------
+       value : out
+               Scrambled value.
+       """
+       def __init__(self):
+               self.value = Signal(32)
+
+               ###
+
+               context = Signal(16, reset=0xf0f6)
+               next_value = Signal(32)
+               self.sync += context.eq(next_value[16:32])
+
+               # XXX: from SATA specification, replace it with
+               # a generic implementation using polynoms.
+               lfsr_coefs = (
+                       (15, 13, 4, 0), #0
+                       (15, 14, 13, 5, 4, 1, 0),
+                       (14, 13, 6, 5, 4, 2,1, 0),
+                       (15, 14, 7, 6, 5, 3,2, 1),
+                       (13, 8, 7, 6, 3, 2, 0),
+                       (14, 9, 8, 7, 4, 3, 1),
+                       (15, 10, 9, 8, 5, 4, 2),
+                       (15, 13, 11, 10, 9, 6, 5, 4, 3, 0),
+                       (15, 14, 13, 12, 11, 10,7, 6, 5, 1, 0),
+                       (14, 12, 11, 8, 7, 6, 4, 2, 1, 0),
+                       (15, 13, 12, 9, 8, 7, 5, 3, 2, 1),
+                       (15, 14, 10, 9, 8, 6, 3, 2, 0),
+                       (13, 11, 10, 9, 7, 3, 1, 0),
+                       (14, 12, 11, 10, 8, 4, 2, 1),
+                       (15, 13, 12, 11, 9, 5, 3, 2),
+                       (15, 14, 12, 10, 6, 3, 0),
+
+                       (11, 7, 1, 0), #16
+                       (12, 8, 2, 1),
+                       (13, 9, 3, 2),
+                       (14, 10, 4, 3),
+                       (15, 11, 5, 4),
+                       (15, 13, 12, 6, 5, 4, 0),
+                       (15, 14, 7, 6, 5, 4, 1, 0),
+                       (13, 8, 7, 6, 5, 4, 2, 1, 0),
+                       (14, 9, 8,7, 6, 5, 3, 2, 1),
+                       (15, 10, 9, 8, 7, 6, 4, 3, 2),
+                       (15, 13, 11, 10, 9, 8, 7, 5, 3, 0),
+                       (15, 14, 13, 12, 11, 10, 9, 8, 6, 1, 0),
+                       (14, 12, 11, 10, 9, 7, 4, 2, 1, 0),
+                       (15, 13, 12, 11, 10, 8, 5, 3, 2, 1),
+                       (15, 14, 12, 11, 9, 6, 3, 2, 0),
+                       (12, 10, 7, 3, 1, 0),
+               )
+
+               for n, coefs in enumerate(lfsr_coefs):
+                       eq = [context[i] for i in coefs]
+                       self.comb += next_value[n].eq(optree("^", eq))
+
+               self.comb += self.value.eq(next_value)
+
+@DecorateModule(InsertReset)
+class LiteSATAScrambler(Module):
+       def __init__(self, description):
+               self.sink = sink = Sink(description)
+               self.source = source = Source(description)
+
+               ###
+
+               self.scrambler = Scrambler()
+               self.comb += [
+                       self.scrambler.ce.eq(sink.stb & sink.ack),
+                       Record.connect(sink, source),
+                       source.d.eq(sink.d ^ self.scrambler.value)
+               ]
diff --git a/litesata/core/transport/__init__.py b/litesata/core/transport/__init__.py
new file mode 100644 (file)
index 0000000..e003021
--- /dev/null
@@ -0,0 +1,258 @@
+from 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
+
+class LiteSATATransportTX(Module):
+       def __init__(self, link):
+               self.sink = sink = Sink(transport_tx_description(32))
+
+               ###
+
+               cmd_ndwords = max(fis_reg_h2d_cmd_len, fis_data_cmd_len)
+               encoded_cmd = Signal(cmd_ndwords*32)
+
+               self.counter = counter = Counter(max=cmd_ndwords+1)
+
+               cmd_len = Signal(counter.width)
+               cmd_with_data = Signal()
+
+               cmd_send = Signal()
+               data_send = Signal()
+               cmd_done = Signal()
+
+               def test_type(name):
+                       return sink.type == fis_types[name]
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+               fsm.act("IDLE",
+                       sink.ack.eq(0),
+                       counter.reset.eq(1),
+                       If(sink.stb & sink.sop,
+                               If(test_type("REG_H2D"),
+                                       NextState("SEND_REG_H2D_CMD")
+                               ).Elif(test_type("DATA"),
+                                       NextState("SEND_DATA_CMD")
+                               ).Else(
+                                       sink.ack.eq(1)
+                               )
+                       ).Else(
+                               sink.ack.eq(1)
+                       )
+               )
+               fsm.act("SEND_REG_H2D_CMD",
+                       _encode_cmd(sink, fis_reg_h2d_layout, encoded_cmd),
+                       cmd_len.eq(fis_reg_h2d_cmd_len-1),
+                       cmd_send.eq(1),
+                       If(cmd_done,
+                               sink.ack.eq(1),
+                               NextState("IDLE")
+                       )
+               )
+               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),
+                       cmd_with_data.eq(1),
+                       cmd_send.eq(1),
+                       If(cmd_done,
+                               NextState("SEND_DATA")
+                       )
+               )
+               fsm.act("SEND_DATA",
+                       data_send.eq(1),
+                       sink.ack.eq(link.sink.ack),
+                       If(sink.stb & sink.eop & sink.ack,
+                               NextState("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(sink.stb),
+                               link.sink.sop.eq(counter.value == 0),
+                               link.sink.eop.eq((counter.value == cmd_len) & ~cmd_with_data),
+                               Case(counter.value, cmd_cases),
+                               counter.ce.eq(sink.stb & link.sink.ack),
+                               cmd_done.eq((counter.value == cmd_len) & link.sink.stb & link.sink.ack)
+                       ).Elif(data_send,
+                               link.sink.stb.eq(sink.stb),
+                               link.sink.sop.eq(0),
+                               link.sink.eop.eq(sink.eop),
+                               link.sink.d.eq(sink.data),
+                       )
+
+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)
+               encoded_cmd = Signal(cmd_ndwords*32)
+
+               self.counter = counter = Counter(max=cmd_ndwords+1)
+
+               cmd_len = Signal(counter.width)
+
+               cmd_receive = Signal()
+               data_receive = Signal()
+               cmd_done = Signal()
+               data_done = Signal()
+
+               def test_type(name):
+                       return link.source.d[:8] == fis_types[name]
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+
+               data_sop = Signal()
+
+               fsm.act("IDLE",
+                       link.source.ack.eq(0),
+                       counter.reset.eq(1),
+                       If(link.source.stb & link.source.sop,
+                               If(test_type("REG_D2H"),
+                                       NextState("RECEIVE_REG_D2H_CMD")
+                               ).Elif(test_type("DMA_ACTIVATE_D2H"),
+                                       NextState("RECEIVE_DMA_ACTIVATE_D2H_CMD")
+                               ).Elif(test_type("PIO_SETUP_D2H"),
+                                       NextState("RECEIVE_PIO_SETUP_D2H_CMD")
+                               ).Elif(test_type("DATA"),
+                                       NextState("RECEIVE_DATA_CMD"),
+                               ).Else(
+                                       link.source.ack.eq(1)
+                               )
+                       ).Else(
+                               link.source.ack.eq(1)
+                       )
+               )
+               fsm.act("RECEIVE_REG_D2H_CMD",
+                       cmd_len.eq(fis_reg_d2h_cmd_len-1),
+                       cmd_receive.eq(1),
+                       link.source.ack.eq(1),
+                       If(cmd_done,
+                               NextState("PRESENT_REG_D2H_CMD")
+                       )
+               )
+               fsm.act("PRESENT_REG_D2H_CMD",
+                       source.stb.eq(1),
+                       source.sop.eq(1),
+                       source.eop.eq(1),
+                       _decode_cmd(encoded_cmd, fis_reg_d2h_layout, source),
+                       If(source.stb & source.ack,
+                               NextState("IDLE")
+                       )
+               )
+               fsm.act("RECEIVE_DMA_ACTIVATE_D2H_CMD",
+                       cmd_len.eq(fis_dma_activate_d2h_cmd_len-1),
+                       cmd_receive.eq(1),
+                       link.source.ack.eq(1),
+                       If(cmd_done,
+                               NextState("PRESENT_DMA_ACTIVATE_D2H_CMD")
+                       )
+               )
+               fsm.act("PRESENT_DMA_ACTIVATE_D2H_CMD",
+                       source.stb.eq(1),
+                       source.sop.eq(1),
+                       source.eop.eq(1),
+                       _decode_cmd(encoded_cmd, fis_dma_activate_d2h_layout, source),
+                       If(source.stb & source.ack,
+                               NextState("IDLE")
+                       )
+               )
+               fsm.act("RECEIVE_PIO_SETUP_D2H_CMD",
+                       cmd_len.eq(fis_pio_setup_d2h_cmd_len-1),
+                       cmd_receive.eq(1),
+                       link.source.ack.eq(1),
+                       If(cmd_done,
+                               NextState("PRESENT_PIO_SETUP_D2H_CMD")
+                       )
+               )
+               fsm.act("PRESENT_PIO_SETUP_D2H_CMD",
+                       source.stb.eq(1),
+                       source.sop.eq(1),
+                       source.eop.eq(1),
+                       _decode_cmd(encoded_cmd, fis_pio_setup_d2h_layout, source),
+                       If(source.stb & source.ack,
+                               NextState("IDLE")
+                       )
+               )
+               fsm.act("RECEIVE_DATA_CMD",
+                       cmd_len.eq(fis_data_cmd_len-1),
+                       cmd_receive.eq(1),
+                       link.source.ack.eq(1),
+                       If(cmd_done,
+                               NextState("PRESENT_DATA")
+                       )
+               )
+               fsm.act("PRESENT_DATA",
+                       data_receive.eq(1),
+                       source.stb.eq(link.source.stb),
+                       _decode_cmd(encoded_cmd, fis_data_layout, source),
+                       source.sop.eq(data_sop),
+                       source.eop.eq(link.source.eop),
+                       source.error.eq(link.source.error),
+                       source.data.eq(link.source.d),
+                       link.source.ack.eq(source.ack),
+                       If(source.stb & source.eop & source.ack,
+                               NextState("IDLE")
+                       )
+               )
+
+               self.sync += \
+                       If(fsm.ongoing("RECEIVE_DATA_CMD"),
+                               data_sop.eq(1)
+                       ).Elif(fsm.ongoing("PRESENT_DATA"),
+                               If(source.stb & source.ack,
+                                       data_sop.eq(0)
+                               )
+                       )
+
+               cmd_cases = {}
+               for i in range(cmd_ndwords):
+                       cmd_cases[i] = [encoded_cmd[32*i:32*(i+1)].eq(link.source.d)]
+
+               self.comb += \
+                       If(cmd_receive & link.source.stb,
+                               counter.ce.eq(1)
+                       )
+               self.sync += \
+                       If(cmd_receive,
+                               Case(counter.value, cmd_cases),
+                       )
+               self.comb += cmd_done.eq((counter.value == cmd_len) & link.source.ack)
+
+class LiteSATATransport(Module):
+       def __init__(self, link):
+               self.tx = LiteSATATransportTX(link)
+               self.rx = LiteSATATransportRX(link)
+               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/litesata/frontend/__init__.py b/litesata/frontend/__init__.py
new file mode 100644 (file)
index 0000000..6378516
--- /dev/null
@@ -0,0 +1,4 @@
+from litesata.common import *
+from litesata.frontend.crossbar import LiteSATACrossbar
+from litesata.frontend.arbiter import LiteSATAArbiter
+from litesata.frontend.bist import LiteSATABIST
diff --git a/litesata/frontend/arbiter.py b/litesata/frontend/arbiter.py
new file mode 100644 (file)
index 0000000..049946c
--- /dev/null
@@ -0,0 +1,31 @@
+from litesata.common import *
+from litesata.frontend.common import *
+
+from migen.genlib.roundrobin import *
+
+class LiteSATAArbiter(Module):
+       def __init__(self, slaves, master):
+               if len(slaves) == 1:
+                       self.comb += slaves[0].connect(master)
+               else:
+                       self.rr = RoundRobin(len(slaves))
+                       self.grant = self.rr.grant
+                       cases = {}
+                       for i, slave in enumerate(slaves):
+                               sink, source = slave.sink, slave.source
+                               start = Signal()
+                               done = Signal()
+                               ongoing = Signal()
+                               self.comb += [
+                                       start.eq(sink.stb & sink.sop),
+                                       done.eq(source.stb & source.last & source.eop & source.ack)
+                               ]
+                               self.sync += \
+                                       If(start,
+                                               ongoing.eq(1)
+                                       ).Elif(done,
+                                               ongoing.eq(0)
+                                       )
+                               self.comb += self.rr.request[i].eq((start | ongoing) & ~done)
+                               cases[i] = [slaves[i].connect(master)]
+                       self.comb += Case(self.grant, cases)
diff --git a/litesata/frontend/bist.py b/litesata/frontend/bist.py
new file mode 100644 (file)
index 0000000..be994cb
--- /dev/null
@@ -0,0 +1,247 @@
+from litesata.common import *
+from litesata.core.link.scrambler import Scrambler
+
+from migen.fhdl.decorators import ModuleDecorator
+from migen.bank.description import *
+
+class LiteSATABISTGenerator(Module):
+       def __init__(self, sata_master_port):
+               self.start = Signal()
+               self.sector = Signal(48)
+               self.count = Signal(16)
+               self.random = Signal()
+
+               self.done = Signal()
+               self.errors = Signal(32) # Note: Not used for writes
+
+               ###
+
+               source, sink = sata_master_port.source, sata_master_port.sink
+
+               self.counter = counter = Counter(bits_sign=32)
+
+               self.scrambler = scrambler = InsertReset(Scrambler())
+               self.comb += [
+                       scrambler.reset.eq(counter.reset),
+                       scrambler.ce.eq(counter.ce)
+               ]
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+               fsm.act("IDLE",
+                       self.done.eq(1),
+                       counter.reset.eq(1),
+                       If(self.start,
+                               NextState("SEND_CMD_AND_DATA")
+                       )
+               )
+               self.comb += [
+                       source.sop.eq(counter.value == 0),
+                       source.eop.eq(counter.value == (logical_sector_size//4*self.count)-1),
+                       source.write.eq(1),
+                       source.sector.eq(self.sector),
+                       source.count.eq(self.count),
+                       If(self.random,
+                               source.data.eq(scrambler.value)
+                       ).Else(
+                               source.data.eq(counter.value)
+                       )
+               ]
+               fsm.act("SEND_CMD_AND_DATA",
+                       source.stb.eq(1),
+                       If(source.stb & source.ack,
+                               counter.ce.eq(1),
+                               If(source.eop,
+                                       NextState("WAIT_ACK")
+                               )
+                       )
+               )
+               fsm.act("WAIT_ACK",
+                       sink.ack.eq(1),
+                       If(sink.stb,
+                               NextState("IDLE")
+                       )
+               )
+
+class LiteSATABISTChecker(Module):
+       def __init__(self, sata_master_port):
+               self.start = Signal()
+               self.sector = Signal(48)
+               self.count = Signal(16)
+               self.random = Signal()
+
+               self.done = Signal()
+               self.errors = Signal(32)
+
+               ###
+
+               source, sink = sata_master_port.source, sata_master_port.sink
+
+               self.counter = counter = Counter(bits_sign=32)
+               self.error_counter = Counter(self.errors, bits_sign=32)
+
+               self.scrambler = scrambler = InsertReset(Scrambler())
+               self.comb += [
+                       scrambler.reset.eq(counter.reset),
+                       scrambler.ce.eq(counter.ce)
+               ]
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+               fsm.act("IDLE",
+                       self.done.eq(1),
+                       counter.reset.eq(1),
+                       If(self.start,
+                               self.error_counter.reset.eq(1),
+                               NextState("SEND_CMD")
+                       )
+               )
+               self.comb += [
+                       source.sop.eq(1),
+                       source.eop.eq(1),
+                       source.read.eq(1),
+                       source.sector.eq(self.sector),
+                       source.count.eq(self.count),
+               ]
+               fsm.act("SEND_CMD",
+                       source.stb.eq(1),
+                       If(source.ack,
+                               counter.reset.eq(1),
+                               NextState("WAIT_ACK")
+                       )
+               )
+               fsm.act("WAIT_ACK",
+                       If(sink.stb & sink.read,
+                               NextState("RECEIVE_DATA")
+                       )
+               )
+               expected_data = Signal(32)
+               self.comb += \
+                       If(self.random,
+                               expected_data.eq(scrambler.value)
+                       ).Else(
+                               expected_data.eq(counter.value)
+                       )
+               fsm.act("RECEIVE_DATA",
+                       sink.ack.eq(1),
+                       If(sink.stb,
+                               counter.ce.eq(1),
+                               If(sink.data != expected_data,
+                                       self.error_counter.ce.eq(1)
+                               ),
+                               If(sink.eop,
+                                       If(sink.last,
+                                               NextState("IDLE")
+                                       ).Else(
+                                               NextState("WAIT_ACK")
+                                       )
+                               )
+                       )
+               )
+
+class LiteSATABISTUnitCSR(Module, AutoCSR):
+       def __init__(self, bist_unit):
+               self._start = CSR()
+               self._sector = CSRStorage(48)
+               self._count = CSRStorage(16)
+               self._random = CSRStorage()
+               self._done = CSRStatus()
+               self._errors = CSRStatus(32)
+               self._cycles = CSRStatus(32)
+
+               ###
+
+               self.bist_unit = bist_unit
+               self.comb += [
+                       bist_unit.start.eq(self._start.r & self._start.re),
+                       bist_unit.sector.eq(self._sector.storage),
+                       bist_unit.count.eq(self._count.storage),
+                       bist_unit.random.eq(self._random.storage),
+
+                       self._done.status.eq(bist_unit.done),
+                       self._errors.status.eq(bist_unit.errors)
+               ]
+
+               self.cycles_counter = Counter(self._cycles.status)
+               self.sync += [
+                       self.cycles_counter.reset.eq(bist_unit.start),
+                       self.cycles_counter.ce.eq(~bist_unit.done)
+               ]
+
+class LiteSATABISTIdentify(Module):
+       def __init__(self, sata_master_port):
+               self.start = Signal()
+               self.done  = Signal()
+
+               self.fifo = fifo = SyncFIFO([("data", 32)], 512, buffered=True)
+               self.source = self.fifo.source
+
+               ###
+
+               source, sink = sata_master_port.source, sata_master_port.sink
+
+               self.fsm = fsm = FSM(reset_state="IDLE")
+               fsm.act("IDLE",
+                       self.done.eq(1),
+                       If(self.start,
+                               NextState("SEND_CMD")
+                       )
+               )
+               self.comb += [
+                       source.sop.eq(1),
+                       source.eop.eq(1),
+                       source.identify.eq(1),
+               ]
+               fsm.act("SEND_CMD",
+                       source.stb.eq(1),
+                       If(source.stb & source.ack,
+                               NextState("WAIT_ACK")
+                       )
+               )
+               fsm.act("WAIT_ACK",
+                       If(sink.stb & sink.identify,
+                               NextState("RECEIVE_DATA")
+                       )
+               )
+               self.comb += fifo.sink.data.eq(sink.data)
+               fsm.act("RECEIVE_DATA",
+                       sink.ack.eq(fifo.sink.ack),
+                       If(sink.stb,
+                               fifo.sink.stb.eq(1),
+                               If(sink.eop,
+                                       NextState("IDLE")
+                               )
+                       )
+               )
+
+class LiteSATABISTIdentifyCSR(Module, AutoCSR):
+       def __init__(self, bist_identify):
+               self._start = CSR()
+               self._done = CSRStatus()
+               self._source_stb = CSRStatus()
+               self._source_ack = CSR()
+               self._source_data = CSRStatus(32)
+
+               ###
+
+               self.bist_identify = bist_identify
+               self.comb += [
+                       bist_identify.start.eq(self._start.r & self._start.re),
+                       self._done.status.eq(bist_identify.done),
+
+                       self._source_stb.status.eq(bist_identify.source.stb),
+                       self._source_data.status.eq(bist_identify.source.data),
+                       bist_identify.source.ack.eq(self._source_ack.r & self._source_ack.re)
+               ]
+
+class LiteSATABIST(Module, AutoCSR):
+       def __init__(self, crossbar, with_csr=False):
+               generator = LiteSATABISTGenerator(crossbar.get_port())
+               checker = LiteSATABISTChecker(crossbar.get_port())
+               identify = LiteSATABISTIdentify(crossbar.get_port())
+               if with_csr:
+                       self.generator = LiteSATABISTUnitCSR(generator)
+                       self.checker = LiteSATABISTUnitCSR(checker)
+                       self.identify = LiteSATABISTIdentifyCSR(identify)
+               else:
+                       self.generator = generator
+                       self.checker = checker
+                       self.identify = identify
diff --git a/litesata/frontend/common.py b/litesata/frontend/common.py
new file mode 100644 (file)
index 0000000..308a6c6
--- /dev/null
@@ -0,0 +1,23 @@
+from litesata.common import *
+
+class LiteSATAMasterPort:
+       def __init__(self, dw):
+               self.source = Source(command_tx_description(dw))
+               self.sink = Sink(command_rx_description(dw))
+
+       def connect(self, slave):
+               return [
+                       Record.connect(self.source, slave.sink),
+                       Record.connect(slave.source, self.sink)
+               ]
+
+class LiteSATASlavePort:
+       def __init__(self, dw):
+               self.sink = Sink(command_tx_description(dw))
+               self.source = Source(command_rx_description(dw))
+
+       def connect(self, master):
+               return [
+                       Record.connect(self.sink, master.source),
+                       Record.connect(master.sink, self.source)
+               ]
diff --git a/litesata/frontend/crossbar.py b/litesata/frontend/crossbar.py
new file mode 100644 (file)
index 0000000..f4ca37a
--- /dev/null
@@ -0,0 +1,28 @@
+from litesata.common import *
+from litesata.frontend.common import *
+from litesata.frontend.arbiter import LiteSATAArbiter
+
+class LiteSATACrossbar(Module):
+       def __init__(self, core):
+               self.slaves = []
+               self.master = LiteSATAMasterPort(32)
+               self.comb += [
+                       self.master.source.connect(core.sink),
+                       core.source.connect(self.master.sink)
+               ]
+
+       def get_port(self):
+               master = LiteSATAMasterPort(32)
+               slave = LiteSATASlavePort(32)
+               self.comb += master.connect(slave)
+               self.slaves.append(slave)
+               return master
+
+       def get_ports(self, n):
+               masters = []
+               for i in range(n):
+                       masters.append(self.get_port())
+               return masters
+
+       def do_finalize(self):
+               self.arbiter = LiteSATAArbiter(self.slaves, self.master)
diff --git a/litesata/phy/__init__.py b/litesata/phy/__init__.py
new file mode 100644 (file)
index 0000000..fcb206f
--- /dev/null
@@ -0,0 +1,23 @@
+from litesata.common import *
+from litesata.phy.ctrl import *
+from litesata.phy.datapath import *
+
+class LiteSATAPHY(Module):
+       def __init__(self, device, pads, speed, clk_freq):
+               self.speed = speed
+               # Transceiver / Clocks
+               if device[:3] == "xc7": # Kintex 7
+                       from litesata.phy.k7.trx import K7LiteSATAPHYTRX
+                       from litesata.phy.k7.crg import K7LiteSATAPHYCRG
+                       self.trx = K7LiteSATAPHYTRX(pads, speed)
+                       self.crg = K7LiteSATAPHYCRG(pads, self.trx, speed, clk_freq)
+               else:
+                       msg = "Device" + device + "not (yet) supported."
+                       raise NotImplementedError(msg)
+
+               # Control
+               self.ctrl = LiteSATAPHYCtrl(self.trx, self.crg, clk_freq)
+
+               # Datapath
+               self.datapath = LiteSATAPHYDatapath(self.trx, self.ctrl)
+               self.sink, self.source = self.datapath.sink, self.datapath.source
diff --git a/litesata/phy/ctrl.py b/litesata/phy/ctrl.py
new file mode 100644 (file)
index 0000000..23d6408
--- /dev/null
@@ -0,0 +1,148 @@
+from litesata.common import *
+
+def us(t, clk_freq):
+       clk_period_us = 1000000/clk_freq
+       return math.ceil(t/clk_period_us)
+
+class LiteSATAPHYCtrl(Module):
+       def __init__(self, trx, crg, clk_freq):
+               self.ready = Signal()
+               self.need_reset = Signal()
+               self.sink = sink = Sink(phy_description(32))
+               self.source = source = Source(phy_description(32))
+
+               ###
+               self.comb += [
+                       source.stb.eq(1),
+                       sink.ack.eq(1)
+               ]
+
+               retry_timeout = Timeout(us(10000, clk_freq))
+               align_timeout = Timeout(us(873, clk_freq))
+               self.submodules += align_timeout, retry_timeout
+
+               align_detect = Signal()
+               non_align_cnt = Signal(4)
+
+               self.fsm = fsm = FSM(reset_state="RESET")
+               fsm.act("RESET",
+                       trx.tx_idle.eq(1),
+                       retry_timeout.reset.eq(1),
+                       align_timeout.reset.eq(1),
+                       If(crg.ready,
+                               NextState("COMINIT")
+                       ),
+               )
+               fsm.act("COMINIT",
+                       trx.tx_idle.eq(1),
+                       trx.tx_cominit_stb.eq(1),
+                       If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
+                               NextState("AWAIT_COMINIT")
+                       ),
+               )
+               fsm.act("AWAIT_COMINIT",
+                       trx.tx_idle.eq(1),
+                       retry_timeout.ce.eq(1),
+                       If(trx.rx_cominit_stb,
+                               NextState("AWAIT_NO_COMINIT")
+                       ).Else(
+                               If(retry_timeout.reached,
+                                       NextState("RESET")
+                               )
+                       ),
+               )
+               fsm.act("AWAIT_NO_COMINIT",
+                       trx.tx_idle.eq(1),
+                       retry_timeout.reset.eq(1),
+                       If(~trx.rx_cominit_stb,
+                               NextState("CALIBRATE")
+                       ),
+               )
+               fsm.act("CALIBRATE",
+                       trx.tx_idle.eq(1),
+                       NextState("COMWAKE"),
+               )
+               fsm.act("COMWAKE",
+                       trx.tx_idle.eq(1),
+                       trx.tx_comwake_stb.eq(1),
+                       If(trx.tx_comwake_ack,
+                               NextState("AWAIT_COMWAKE")
+                       ),
+               )
+               fsm.act("AWAIT_COMWAKE",
+                       trx.tx_idle.eq(1),
+                       retry_timeout.ce.eq(1),
+                       If(trx.rx_comwake_stb,
+                               NextState("AWAIT_NO_COMWAKE")
+                       ).Else(
+                               If(retry_timeout.reached,
+                                       NextState("RESET")
+                               )
+                       ),
+               )
+               fsm.act("AWAIT_NO_COMWAKE",
+                       trx.tx_idle.eq(1),
+                       If(~trx.rx_comwake_stb,
+                               NextState("AWAIT_NO_RX_IDLE")
+                       ),
+               )
+               fsm.act("AWAIT_NO_RX_IDLE",
+                       trx.tx_idle.eq(0),
+                       source.data.eq(0x4A4A4A4A), #D10.2
+                       source.charisk.eq(0b0000),
+                       If(~trx.rx_idle,
+                               NextState("AWAIT_ALIGN"),
+                               crg.reset.eq(1),
+                               trx.pmarxreset.eq(1)
+                       ),
+               )
+               fsm.act("AWAIT_ALIGN",
+                       trx.tx_idle.eq(0),
+                       source.data.eq(0x4A4A4A4A), #D10.2
+                       source.charisk.eq(0b0000),
+                       trx.rx_align.eq(1),
+                       align_timeout.ce.eq(1),
+                       If(align_detect & ~trx.rx_idle,
+                               NextState("SEND_ALIGN")
+                       ).Elif(align_timeout.reached,
+                               NextState("RESET")
+                       ),
+               )
+               fsm.act("SEND_ALIGN",
+                       trx.tx_idle.eq(0),
+                       trx.rx_align.eq(1),
+                       source.data.eq(primitives["ALIGN"]),
+                       source.charisk.eq(0b0001),
+                       If(non_align_cnt == 3,
+                               NextState("READY")
+                       ),
+               )
+               fsm.act("READY",
+                       trx.tx_idle.eq(0),
+                       trx.rx_align.eq(1),
+                       source.data.eq(primitives["SYNC"]),
+                       source.charisk.eq(0b0001),
+                       If(trx.rx_idle,
+                               NextState("RESET")
+                       ),
+                       self.ready.eq(1),
+               )
+
+               self.reset_timeout = Timeout(clk_freq//16)
+               self.comb += [
+                       self.reset_timeout.ce.eq(~self.ready),
+                       self.need_reset.eq(self.reset_timeout.reached)
+               ]
+
+               self.comb +=  \
+                       align_detect.eq(self.sink.stb & (self.sink.data == primitives["ALIGN"]))
+               self.sync += \
+                       If(fsm.ongoing("SEND_ALIGN"),
+                               If(sink.stb,
+                                       If(sink.data[0:8] == 0x7C,
+                                               non_align_cnt.eq(non_align_cnt + 1)
+                                       ).Else(
+                                               non_align_cnt.eq(0)
+                                       )
+                               )
+                       )
diff --git a/litesata/phy/datapath.py b/litesata/phy/datapath.py
new file mode 100644 (file)
index 0000000..c47e752
--- /dev/null
@@ -0,0 +1,157 @@
+from litesata.common import *
+
+class LiteSATAPHYDatapathRX(Module):
+       def __init__(self):
+               self.sink = Sink(phy_description(16))
+               self.source = Source(phy_description(32))
+
+               ###
+
+       # width convertion (16 to 32) and byte alignment
+               byte_alignment = Signal()
+               last_charisk = Signal(2)
+               last_data = Signal(16)
+               self.sync.sata_rx += \
+                       If(self.sink.stb & self.sink.ack,
+                               If(self.sink.charisk != 0,
+                                       byte_alignment.eq(self.sink.charisk[1])
+                               ),
+                               last_charisk.eq(self.sink.charisk),
+                               last_data.eq(self.sink.data)
+                       )
+               converter = Converter(phy_description(16), phy_description(32), reverse=False)
+               self.converter = InsertReset(RenameClockDomains(converter, "sata_rx"))
+               self.comb += [
+                       self.converter.sink.stb.eq(self.sink.stb),
+                       If(byte_alignment,
+                               self.converter.sink.charisk.eq(Cat(last_charisk[1], self.sink.charisk[0])),
+                               self.converter.sink.data.eq(Cat(last_data[8:], self.sink.data[:8]))
+                       ).Else(
+                               self.converter.sink.charisk.eq(self.sink.charisk),
+                               self.converter.sink.data.eq(self.sink.data)
+                       ),
+                       self.sink.ack.eq(self.converter.sink.ack),
+                       self.converter.reset.eq(self.converter.source.charisk[2:] != 0)
+               ]
+
+       # clock domain crossing
+               # (SATA3) 300MHz sata_rx clk to sys_clk
+               # (SATA2) 150MHz sata_rx clk to sys_clk
+               # (SATA1) 75MHz sata_rx clk to sys_clk
+               # requirements:
+               # due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
+               # source destination is always able to accept data (ack always 1)
+               fifo = AsyncFIFO(phy_description(32), 4)
+               self.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
+               self.comb += [
+                       Record.connect(self.converter.source, fifo.sink),
+                       Record.connect(fifo.source, self.source)
+               ]
+
+class LiteSATAPHYDatapathTX(Module):
+       def __init__(self):
+               self.sink = Sink(phy_description(32))
+               self.source = Source(phy_description(16))
+
+               ###
+
+       # clock domain crossing
+               # (SATA3) sys_clk to 300MHz sata_tx clk
+               # (SATA2) sys_clk to 150MHz sata_tx clk
+               # (SATA1) sys_clk to 75MHz sata_tx clk
+               # requirements:
+               # source destination is always able to accept data (ack always 1)
+               fifo = AsyncFIFO(phy_description(32), 4)
+               self.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
+               self.comb += Record.connect(self.sink, fifo.sink)
+
+       # width convertion (32 to 16)
+               converter = Converter(phy_description(32), phy_description(16), reverse=False)
+               self.converter =  RenameClockDomains(converter, "sata_tx")
+               self.comb += [
+                       Record.connect(self.fifo.source, self.converter.sink),
+                       Record.connect(self.converter.source, self.source)
+               ]
+
+class LiteSATAPHYAlignInserter(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 LiteSATAPHYAlignRemover(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 LiteSATAPHYDatapath(Module):
+       def __init__(self, trx, ctrl):
+               self.sink = Sink(phy_description(32))
+               self.source = Source(phy_description(32))
+
+               ###
+
+       # TX path
+               self.align_inserter = LiteSATAPHYAlignInserter(ctrl)
+               self.mux = Multiplexer(phy_description(32), 2)
+               self.tx = LiteSATAPHYDatapathTX()
+               self.comb += [
+                       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)
+               ]
+
+       # RX path
+               self.rx = LiteSATAPHYDatapathRX()
+               self.demux = Demultiplexer(phy_description(32), 2)
+               self.align_remover = LiteSATAPHYAlignRemover()
+               self.comb += [
+                       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)
+               ]
diff --git a/litesata/phy/k7/crg.py b/litesata/phy/k7/crg.py
new file mode 100644 (file)
index 0000000..9bfc67e
--- /dev/null
@@ -0,0 +1,155 @@
+from litesata.common import *
+
+class K7LiteSATAPHYCRG(Module):
+       def __init__(self, pads, gtx, speed, clk_freq):
+               self.reset = Signal()
+               self.ready = Signal()
+
+               self.cd_sata_tx = ClockDomain()
+               self.cd_sata_rx = ClockDomain()
+
+       # CPLL
+               # (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
+               # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output dividers.
+               refclk = Signal()
+               self.specials += Instance("IBUFDS_GTE2",
+                       i_CEB=0,
+                       i_I=pads.refclk_p,
+                       i_IB=pads.refclk_n,
+                       o_O=refclk
+               )
+               self.comb += gtx.gtrefclk0.eq(refclk)
+
+       # TX clocking
+               # (SATA3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits)
+               # (SATA2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits)
+               # (SATA1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits)
+               mmcm_reset = Signal()
+               mmcm_locked = Signal()
+               mmcm_fb = Signal()
+               mmcm_clk_i = Signal()
+               mmcm_clk0_o = Signal()
+               mmcm_div_config = {
+                       "SATA1" :       16.0,
+                       "SATA2" :       8.0,
+                       "SATA3" :       4.0
+                       }
+               mmcm_div = mmcm_div_config[speed]
+               self.specials += [
+                       Instance("BUFG", i_I=gtx.txoutclk, o_O=mmcm_clk_i),
+                       Instance("MMCME2_ADV",
+                               p_BANDWIDTH="HIGH", p_COMPENSATION="ZHOLD", i_RST=mmcm_reset, o_LOCKED=mmcm_locked,
+
+                               # DRP
+                               i_DCLK=0, i_DEN=0, i_DWE=0, #o_DRDY=,
+                               i_DADDR=0, i_DI=0, #o_DO=,
+
+                               # VCO
+                               p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.666,
+                               p_CLKFBOUT_MULT_F=8.000, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1,
+                               i_CLKIN1=mmcm_clk_i, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb,
+
+                               # CLK0
+                               p_CLKOUT0_DIVIDE_F=mmcm_div, p_CLKOUT0_PHASE=0.000, o_CLKOUT0=mmcm_clk0_o,
+                       ),
+                       Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk),
+               ]
+               self.comb += [
+                       gtx.txusrclk.eq(self.cd_sata_tx.clk),
+                       gtx.txusrclk2.eq(self.cd_sata_tx.clk)
+               ]
+
+       # RX clocking
+               # (SATA3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK
+               # (SATA2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
+               # (SATA1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
+               self.specials += [
+                       Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
+               ]
+               self.comb += [
+                       gtx.rxusrclk.eq(self.cd_sata_rx.clk),
+                       gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
+               ]
+
+       # Configuration Reset
+               # After configuration, GTX's resets have to stay low for at least 500ns
+               # See AR43482
+               reset_en = Signal()
+               clk_period_ns = 1000000000/clk_freq
+               reset_en_cnt_max = math.ceil(500/clk_period_ns)
+               reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1)
+               self.sync += \
+                       If(self.reset,
+                               reset_en_cnt.eq(reset_en_cnt.reset)
+                       ).Elif(~reset_en,
+                               reset_en_cnt.eq(reset_en_cnt-1)
+                       )
+               self.comb += reset_en.eq(reset_en_cnt == 0)
+
+       # TX Reset FSM
+               tx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
+               self.submodules += tx_reset_fsm
+               self.comb += tx_reset_fsm.reset.eq(self.reset)
+               tx_reset_fsm.act("IDLE",
+                       If(reset_en,
+                               NextState("RESET_GTX"),
+                       )
+               )
+               tx_reset_fsm.act("RESET_GTX",
+                       gtx.gttxreset.eq(1),
+                       If(gtx.cplllock & mmcm_locked,
+                               NextState("RELEASE_GTX")
+                       )
+               )
+               tx_reset_fsm.act("RELEASE_GTX",
+                       gtx.txuserrdy.eq(1),
+                       If(gtx.txresetdone,
+                               NextState("READY")
+                       )
+               )
+               tx_reset_fsm.act("READY",
+                       gtx.txuserrdy.eq(1)
+               )
+
+       # RX Reset FSM
+               rx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
+               self.submodules += rx_reset_fsm
+               self.comb += rx_reset_fsm.reset.eq(self.reset)
+
+               rx_reset_fsm.act("IDLE",
+                       If(reset_en,
+                               NextState("RESET_GTX"),
+                       )
+               )
+               rx_reset_fsm.act("RESET_GTX",
+                       gtx.gtrxreset.eq(1),
+                       If(gtx.cplllock & mmcm_locked,
+                               NextState("RELEASE_GTX")
+                       )
+               )
+               rx_reset_fsm.act("RELEASE_GTX",
+                       gtx.rxuserrdy.eq(1),
+                       If(gtx.rxresetdone,
+                               NextState("READY")
+                       )
+               )
+               rx_reset_fsm.act("READY",
+                       gtx.rxuserrdy.eq(1)
+               )
+
+       # Ready
+               self.tx_ready = tx_reset_fsm.ongoing("READY")
+               self.rx_ready = rx_reset_fsm.ongoing("READY")
+               self.comb += self.ready.eq(self.tx_ready & self.rx_ready)
+
+       # Reset PLL
+               self.comb += gtx.cpllreset.eq(ResetSignal() | self.reset | ~reset_en)
+
+       # Reset MMCM
+               self.comb += mmcm_reset.eq(ResetSignal() | self.reset | ~gtx.cplllock)
+
+       # Reset for SATA TX/RX clock domains
+               self.specials += [
+                       AsyncResetSynchronizer(self.cd_sata_tx, ~self.tx_ready),
+                       AsyncResetSynchronizer(self.cd_sata_rx, ~self.rx_ready),
+               ]
diff --git a/litesata/phy/k7/trx.py b/litesata/phy/k7/trx.py
new file mode 100644 (file)
index 0000000..ad9a9c8
--- /dev/null
@@ -0,0 +1,852 @@
+from litesata.common import *
+
+def ones(width):
+       return 2**width-1
+
+class _PulseSynchronizer(PulseSynchronizer):
+       def __init__(self, i, idomain, o, odomain):
+               PulseSynchronizer.__init__(self, idomain, odomain)
+               self.comb += [
+                       self.i.eq(i),
+                       o.eq(self.o)
+               ]
+
+class _RisingEdge(Module):
+       def __init__(self, i, o):
+               i_d = Signal()
+               self.sync += i_d.eq(i)
+               self.comb += o.eq(i & ~i_d)
+
+class K7LiteSATAPHYTRX(Module):
+       def __init__(self, pads, speed):
+       # Common signals
+
+               # control
+               self.tx_idle = Signal()                 #i
+
+               self.tx_cominit_stb = Signal()  #i
+               self.tx_cominit_ack = Signal()  #o
+               self.tx_comwake_stb = Signal()  #i
+               self.tx_comwake_ack = Signal()  #o
+
+               self.rx_idle = Signal()                 #o
+               self.rx_align = Signal()                #i
+
+               self.rx_cominit_stb = Signal()  #o
+               self.rx_comwake_stb = Signal()  #o
+
+               # datapath
+               self.sink = Sink(phy_description(16))
+               self.source = Source(phy_description(16))
+
+       # K7 specific signals
+               # Channel - Ref Clock Ports
+               self.gtrefclk0 = Signal()
+
+               # Channel PLL
+               self.cplllock = Signal()
+               self.cpllreset = Signal()
+
+               # Receive Ports
+               self.rxuserrdy = Signal()
+               self.rxalign = Signal()
+
+               # Receive Ports - 8b10b Decoder
+               self.rxcharisk = Signal(2)
+               self.rxdisperr = Signal(2)
+
+               # Receive Ports - RX Data Path interface
+               self.gtrxreset = Signal()
+               self.pmarxreset = Signal()
+               self.rxdata = Signal(16)
+               self.rxoutclk = Signal()
+               self.rxusrclk = Signal()
+               self.rxusrclk2 = Signal()
+
+               # Receive Ports - RX Driver,OOB signalling,Coupling and Eq.,CDR
+               self.rxelecidle = Signal()
+
+               # Receive Ports - RX PLL Ports
+               self.rxresetdone = Signal()
+
+               # Receive Ports - RX Ports for SATA
+               self.rxcominitdet = Signal()
+               self.rxcomwakedet = Signal()
+
+               # Transmit Ports
+               self.txuserrdy = Signal()
+
+               # Transmit Ports - 8b10b Encoder Control Ports
+               self.txcharisk = Signal(2)
+
+               # Transmit Ports - TX Data Path interface
+               self.gttxreset = Signal()
+               self.txdata = Signal(16)
+               self.txoutclk = Signal()
+               self.txusrclk = Signal()
+               self.txusrclk2 = Signal()
+
+               # Transmit Ports - TX PLL Ports
+               self.txresetdone = Signal()
+
+               # Transmit Ports - TX Ports for PCI Express
+               self.txelecidle = Signal(reset=1)
+
+               # Transmit Ports - TX Ports for SATA
+               self.txcomfinish = Signal()
+               self.txcominit = Signal()
+               self.txcomwake = Signal()
+               self.txrate = Signal(3)
+               self.rxcdrlock = Signal()
+
+       # Config at startup
+               div_config = {
+                       "SATA1" :       4,
+                       "SATA2" :       2,
+                       "SATA3" :       1
+                       }
+               rxout_div = div_config[speed]
+               txout_div = div_config[speed]
+
+               cdr_config = {
+                       "SATA1" :       0x0380008BFF40100008,
+                       "SATA2" :       0x0388008BFF40200008,
+                       "SATA3" :       0X0380008BFF10200010
+               }
+               rxcdr_cfg = cdr_config[speed]
+
+       # Specific / Generic signals encoding/decoding
+               self.comb += [
+                       self.txelecidle.eq(self.tx_idle),
+                       self.tx_cominit_ack.eq(self.tx_cominit_stb & self.txcomfinish),
+                       self.tx_comwake_ack.eq(self.tx_comwake_stb & self.txcomfinish),
+                       self.rx_idle.eq(self.rxelecidle),
+                       self.rxalign.eq(self.rx_align),
+                       self.rx_cominit_stb.eq(self.rxcominitdet),
+                       self.rx_comwake_stb.eq(self.rxcomwakedet),
+               ]
+               self.submodules += [
+                       _RisingEdge(self.tx_cominit_stb, self.txcominit),
+                       _RisingEdge(self.tx_comwake_stb, self.txcomwake),
+               ]
+
+               self.comb += [
+                       self.txcharisk.eq(self.sink.charisk),
+                       self.txdata.eq(self.sink.data),
+                       self.sink.ack.eq(1),
+
+                       self.source.stb.eq(1),
+                       self.source.charisk.eq(self.rxcharisk),
+                       self.source.data.eq(self.rxdata)
+               ]
+
+       # Internals and clock domain crossing
+               # sys_clk --> sata_tx clk
+               txuserrdy = Signal()
+               txelecidle = Signal(reset=1)
+               txcominit = Signal()
+               txcomwake = Signal()
+               txrate = Signal(3)
+
+               self.specials += [
+                       MultiReg(self.txuserrdy, txuserrdy, "sata_tx"),
+                       MultiReg(self.txelecidle, txelecidle, "sata_tx"),
+                       MultiReg(self.txrate, txrate, "sata_tx")
+               ]
+               self.submodules += [
+                       _PulseSynchronizer(self.txcominit, "sys", txcominit, "sata_tx"),
+                       _PulseSynchronizer(self.txcomwake, "sys", txcomwake, "sata_tx"),
+               ]
+
+               # sata_tx clk --> sys clk
+               txresetdone = Signal()
+               txcomfinish = Signal()
+
+               self.specials += [
+                       MultiReg(txresetdone, self.txresetdone, "sys"),
+               ]
+
+               self.submodules += [
+                       _PulseSynchronizer(txcomfinish, "sata_tx", self.txcomfinish, "sys"),
+               ]
+
+               # sys clk --> sata_rx clk
+               rxuserrdy = Signal()
+
+               self.specials += [
+                       MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx"),
+               ]
+
+               # sata_rx clk --> sys clk
+               rxelecidle = Signal()
+               rxelecidle_i = Signal()
+               rxelecidle_cnt_i = Signal(9)
+               rxresetdone = Signal()
+               rxcominitdet = Signal()
+               rxcomwakedet = Signal()
+               rxratedone = Signal()
+               rxcdrlock = Signal()
+
+               self.specials += [
+                       MultiReg(rxelecidle, rxelecidle_i, "sys"),
+                       MultiReg(rxresetdone, self.rxresetdone, "sys"),
+                       MultiReg(rxcominitdet, self.rxcominitdet, "sys"),
+                       MultiReg(rxcomwakedet, self.rxcomwakedet, "sys"),
+                       MultiReg(rxcdrlock, self.rxcdrlock, "sys"),
+               ]
+
+               self.sync += [
+                       If(rxelecidle_i != self.rxelecidle,
+                               If(rxelecidle_cnt_i == 0,
+                                       self.rxelecidle.eq(rxelecidle_i),
+                                       rxelecidle_cnt_i.eq(255)
+                               ).Else(
+                                       rxelecidle_cnt_i.eq(rxelecidle_cnt_i-1)
+                               )
+                       ).Else(
+                               rxelecidle_cnt_i.eq(255)
+                       )
+               ]
+
+               self.rxbyteisaligned = Signal()
+
+       # QPLL input clock
+               self.qpllclk = Signal()
+               self.qpllrefclk = Signal()
+
+       # Instance
+               gtxe2_channel_parameters = {
+                               # Simulation-Only Attributes
+                                       "p_SIM_RECEIVER_DETECT_PASS":"TRUE",
+                                       "p_SIM_TX_EIDLE_DRIVE_LEVEL":"X",
+                                       "p_SIM_RESET_SPEEDUP":"TRUE",
+                                       "p_SIM_CPLLREFCLK_SEL":0b001,
+                                       "p_SIM_VERSION":"4.0",
+
+                               # RX Byte and Word Alignment Attributes
+                                       "p_ALIGN_COMMA_DOUBLE":"FALSE",
+                                       "p_ALIGN_COMMA_ENABLE":ones(10),
+                                       "p_ALIGN_COMMA_WORD":2,
+                                       "p_ALIGN_MCOMMA_DET":"TRUE",
+                                       "p_ALIGN_MCOMMA_VALUE":0b1010000011,
+                                       "p_ALIGN_PCOMMA_DET":"TRUE",
+                                       "p_ALIGN_PCOMMA_VALUE":0b0101111100,
+                                       "p_SHOW_REALIGN_COMMA":"FALSE",
+                                       "p_RXSLIDE_AUTO_WAIT":7,
+                                       "p_RXSLIDE_MODE":"PCS",
+                                       "p_RX_SIG_VALID_DLY":10,
+
+                               # RX 8B/10B Decoder Attributes
+                                       "p_RX_DISPERR_SEQ_MATCH":"TRUE",
+                                       "p_DEC_MCOMMA_DETECT":"TRUE",
+                                       "p_DEC_PCOMMA_DETECT":"TRUE",
+                                       "p_DEC_VALID_COMMA_ONLY":"FALSE",
+
+                               # RX Clock Correction Attributes
+                                       "p_CBCC_DATA_SOURCE_SEL":"DECODED",
+                                       "p_CLK_COR_SEQ_2_USE":"FALSE",
+                                       "p_CLK_COR_KEEP_IDLE":"FALSE",
+                                       "p_CLK_COR_MAX_LAT":9,
+                                       "p_CLK_COR_MIN_LAT":7,
+                                       "p_CLK_COR_PRECEDENCE":"TRUE",
+                                       "p_CLK_COR_REPEAT_WAIT":0,
+                                       "p_CLK_COR_SEQ_LEN":1,
+                                       "p_CLK_COR_SEQ_1_ENABLE":ones(4),
+                                       "p_CLK_COR_SEQ_1_1":0b0100000000,
+                                       "p_CLK_COR_SEQ_1_2":0b0000000000,
+                                       "p_CLK_COR_SEQ_1_3":0b0000000000,
+                                       "p_CLK_COR_SEQ_1_4":0b0000000000,
+                                       "p_CLK_CORRECT_USE":"FALSE",
+                                       "p_CLK_COR_SEQ_2_ENABLE":ones(4),
+                                       "p_CLK_COR_SEQ_2_1":0b0100000000,
+                                       "p_CLK_COR_SEQ_2_2":0,
+                                       "p_CLK_COR_SEQ_2_3":0,
+                                       "p_CLK_COR_SEQ_2_4":0,
+
+                               # RX Channel Bonding Attributes
+                                       "p_CHAN_BOND_KEEP_ALIGN":"FALSE",
+                                       "p_CHAN_BOND_MAX_SKEW":1,
+                                       "p_CHAN_BOND_SEQ_LEN":1,
+                                       "p_CHAN_BOND_SEQ_1_1":0,
+                                       "p_CHAN_BOND_SEQ_1_1":0,
+                                       "p_CHAN_BOND_SEQ_1_2":0,
+                                       "p_CHAN_BOND_SEQ_1_3":0,
+                                       "p_CHAN_BOND_SEQ_1_4":0,
+                                       "p_CHAN_BOND_SEQ_1_ENABLE":ones(4),
+                                       "p_CHAN_BOND_SEQ_2_1":0,
+                                       "p_CHAN_BOND_SEQ_2_2":0,
+                                       "p_CHAN_BOND_SEQ_2_3":0,
+                                       "p_CHAN_BOND_SEQ_2_4":0,
+                                       "p_CHAN_BOND_SEQ_2_ENABLE":ones(4),
+                                       "p_CHAN_BOND_SEQ_2_USE":"FALSE",
+                                       "p_FTS_DESKEW_SEQ_ENABLE":ones(4),
+                                       "p_FTS_LANE_DESKEW_CFG":ones(4),
+                                       "p_FTS_LANE_DESKEW_EN":"FALSE",
+
+                               # RX Margin Analysis Attributes
+                                       "p_ES_CONTROL":0,
+                                       "p_ES_ERRDET_EN":"FALSE",
+                                       "p_ES_EYE_SCAN_EN":"TRUE",
+                                       "p_ES_HORZ_OFFSET":0,
+                                       "p_ES_PMA_CFG":0,
+                                       "p_ES_PRESCALE":0,
+                                       "p_ES_QUALIFIER":0,
+                                       "p_ES_QUAL_MASK":0,
+                                       "p_ES_SDATA_MASK":0,
+                                       "p_ES_VERT_OFFSET":0,
+
+                               # FPGA RX Interface Attributes
+                                       "p_RX_DATA_WIDTH":20,
+
+                               # PMA Attributes
+                                       "p_OUTREFCLK_SEL_INV":0b11,
+                                       "p_PMA_RSV":0x00018480,
+                                       "p_PMA_RSV2":0x2050,
+                                       "p_PMA_RSV3":0,
+                                       "p_PMA_RSV4":0,
+                                       "p_RX_BIAS_CFG":0b100,
+                                       "p_DMONITOR_CFG":0xA00,
+                                       "p_RX_CM_SEL":0b11,
+                                       "p_RX_CM_TRIM":0b010,
+                                       "p_RX_DEBUG_CFG":0,
+                                       "p_RX_OS_CFG":0b10000000,
+                                       "p_TERM_RCAL_CFG":0,
+                                       "p_TERM_RCAL_OVRD":0,
+                                       "p_TST_RSV":0,
+                                       "p_RX_CLK25_DIV":6,
+                                       "p_TX_CLK25_DIV":6,
+                                       "p_UCODEER_CLR":0,
+
+                               # PCI Express Attributes
+                                       "p_PCS_PCIE_EN":"FALSE",
+
+                               # PCS Attributes
+                                       "p_PCS_RSVD_ATTR":0x100,
+
+                               # RX Buffer Attributes
+                                       "p_RXBUF_ADDR_MODE":"FAST",
+                                       "p_RXBUF_EIDLE_HI_CNT":0b1000,
+                                       "p_RXBUF_EIDLE_LO_CNT":0,
+                                       "p_RXBUF_EN":"TRUE",
+                                       "p_RX_BUFFER_CFG":0,
+                                       "p_RXBUF_RESET_ON_CB_CHANGE":"TRUE",
+                                       "p_RXBUF_RESET_ON_COMMAALIGN":"FALSE",
+                                       "p_RXBUF_RESET_ON_EIDLE":"FALSE",
+                                       "p_RXBUF_RESET_ON_RATE_CHANGE":"TRUE",
+                                       "p_RXBUFRESET_TIME":1,
+                                       "p_RXBUF_THRESH_OVFLW":61,
+                                       "p_RXBUF_THRESH_OVRD":"FALSE",
+                                       "p_RXBUF_THRESH_UNDFLW":4,
+                                       "p_RXDLY_CFG":0x1f,
+                                       "p_RXDLY_LCFG":0x30,
+                                       "p_RXDLY_TAP_CFG":0,
+                                       "p_RXPH_CFG":0,
+                                       "p_RXPHDLY_CFG":0x084820,
+                                       "p_RXPH_MONITOR_SEL":0,
+                                       "p_RX_XCLK_SEL":"RXUSR",
+                                       "p_RX_DDI_SEL":0,
+                                       "p_RX_DEFER_RESET_BUF_EN":"TRUE",
+
+                               #CDR Attributes
+                                       "p_RXCDR_CFG":rxcdr_cfg,
+                                       "p_RXCDR_FR_RESET_ON_EIDLE":0,
+                                       "p_RXCDR_HOLD_DURING_EIDLE":0,
+                                       "p_RXCDR_PH_RESET_ON_EIDLE":0,
+                                       "p_RXCDR_LOCK_CFG":0b010101,
+
+                               # RX Initialization and Reset Attributes
+                                       "p_RXCDRFREQRESET_TIME":1,
+                                       "p_RXCDRPHRESET_TIME":1,
+                                       "p_RXISCANRESET_TIME":1,
+                                       "p_RXPCSRESET_TIME":1,
+                                       "p_RXPMARESET_TIME":3,
+
+                               # RX OOB Signaling Attributes
+                                       "p_RXOOB_CFG":0b0000110,
+
+                               # RX Gearbox Attributes
+                                       "p_RXGEARBOX_EN":"FALSE",
+                                       "p_GEARBOX_MODE":0,
+
+                               # PRBS Detection Attribute
+                                       "p_RXPRBS_ERR_LOOPBACK":0,
+
+                               # Power-Down Attributes
+                                       "p_PD_TRANS_TIME_FROM_P2":0x03c,
+                                       "p_PD_TRANS_TIME_NONE_P2":0x3c,
+                                       "p_PD_TRANS_TIME_TO_P2":0x64,
+
+                               # RX OOB Signaling Attributes
+                                       "p_SAS_MAX_COM":64,
+                                       "p_SAS_MIN_COM":36,
+                                       "p_SATA_BURST_SEQ_LEN":0b0101,
+                                       "p_SATA_BURST_VAL":0b100,
+                                       "p_SATA_EIDLE_VAL":0b100,
+                                       "p_SATA_MAX_BURST":8,
+                                       "p_SATA_MAX_INIT":21,
+                                       "p_SATA_MAX_WAKE":7,
+                                       "p_SATA_MIN_BURST":4,
+                                       "p_SATA_MIN_INIT":12,
+                                       "p_SATA_MIN_WAKE":4,
+
+                               # RX Fabric Clock Output Control Attributes
+                                       "p_TRANS_TIME_RATE":0x0e,
+
+                               # TX Buffer Attributes
+                                       "p_TXBUF_EN":"TRUE",
+                                       "p_TXBUF_RESET_ON_RATE_CHANGE":"TRUE",
+                                       "p_TXDLY_CFG":0x1f,
+                                       "p_TXDLY_LCFG":0x030,
+                                       "p_TXDLY_TAP_CFG":0,
+                                       "p_TXPH_CFG":0x0780,
+                                       "p_TXPHDLY_CFG":0x084020,
+                                       "p_TXPH_MONITOR_SEL":0,
+                                       "p_TX_XCLK_SEL":"TXOUT",
+
+                               # FPGA TX Interface Attributes
+                                       "p_TX_DATA_WIDTH":20,
+
+                               # TX Configurable Driver Attributes
+                                       "p_TX_DEEMPH0":0,
+                                       "p_TX_DEEMPH1":0,
+                                       "p_TX_EIDLE_ASSERT_DELAY":0b110,
+                                       "p_TX_EIDLE_DEASSERT_DELAY":0b100,
+                                       "p_TX_LOOPBACK_DRIVE_HIZ":"FALSE",
+                                       "p_TX_MAINCURSOR_SEL":0,
+                                       "p_TX_DRIVE_MODE":"DIRECT",
+                                       "p_TX_MARGIN_FULL_0":0b1001110,
+                                       "p_TX_MARGIN_FULL_1":0b1001001,
+                                       "p_TX_MARGIN_FULL_2":0b1000101,
+                                       "p_TX_MARGIN_FULL_3":0b1000010,
+                                       "p_TX_MARGIN_FULL_4":0b1000000,
+                                       "p_TX_MARGIN_LOW_0":0b1000110,
+                                       "p_TX_MARGIN_LOW_1":0b1000100,
+                                       "p_TX_MARGIN_LOW_2":0b1000010,
+                                       "p_TX_MARGIN_LOW_3":0b1000000,
+                                       "p_TX_MARGIN_LOW_4":0b1000000,
+
+                               # TX Gearbox Attributes
+                                       "p_TXGEARBOX_EN":"FALSE",
+
+                               # TX Initialization and Reset Attributes
+                                       "p_TXPCSRESET_TIME":1,
+                                       "p_TXPMARESET_TIME":1,
+
+                               # TX Receiver Detection Attributes
+                                       "p_TX_RXDETECT_CFG":0x1832,
+                                       "p_TX_RXDETECT_REF":0b100,
+
+                               # CPLL Attributes
+                                       "p_CPLL_CFG":0xBC07DC,
+                                       "p_CPLL_FBDIV":4,
+                                       "p_CPLL_FBDIV_45":5,
+                                       "p_CPLL_INIT_CFG":0x00001e,
+                                       "p_CPLL_LOCK_CFG":0x01e8,
+                                       "p_CPLL_REFCLK_DIV":1,
+                                       "p_RXOUT_DIV":rxout_div,
+                                       "p_TXOUT_DIV":txout_div,
+                                       "p_SATA_CPLL_CFG":"VCO_3000MHZ",
+
+                               # RX Initialization and Reset Attributes
+                                       "p_RXDFELPMRESET_TIME":0b0001111,
+
+                               # RX Equalizer Attributes
+                                       "p_RXLPM_HF_CFG":0b00000011110000,
+                                       "p_RXLPM_LF_CFG":0b00000011110000,
+                                       "p_RX_DFE_GAIN_CFG":0x020fea,
+                                       "p_RX_DFE_H2_CFG":0b000000000000,
+                                       "p_RX_DFE_H3_CFG":0b000001000000,
+                                       "p_RX_DFE_H4_CFG":0b00011110000,
+                                       "p_RX_DFE_H5_CFG":0b00011100000,
+                                       "p_RX_DFE_KL_CFG":0b0000011111110,
+                                       "p_RX_DFE_LPM_CFG":0x0954,
+                                       "p_RX_DFE_LPM_HOLD_DURING_EIDLE":0,
+                                       "p_RX_DFE_UT_CFG":0b10001111000000000,
+                                       "p_RX_DFE_VP_CFG":0b00011111100000011,
+
+                               # Power-Down Attributes
+                                       "p_RX_CLKMUX_PD":1,
+                                       "p_TX_CLKMUX_PD":1,
+
+                               # FPGA RX Interface Attribute
+                                       "p_RX_INT_DATAWIDTH":0,
+
+                               # FPGA TX Interface Attribute
+                                       "p_TX_INT_DATAWIDTH":0,
+
+                               # TX Configurable Driver Attributes
+                                       "p_TX_QPI_STATUS_EN":0,
+
+                               # RX Equalizer Attributes
+                                       "p_RX_DFE_KL_CFG2":0b00110011000100000001100000001100,
+                                       "p_RX_DFE_XYD_CFG":0b0000000000000,
+
+                               # TX Configurable Driver Attributes
+                                       "p_TX_PREDRIVER_MODE":0,
+                       }
+
+               self.specials += \
+                       Instance("GTXE2_CHANNEL",
+                               # CPLL Ports
+                                       #o_CPLLFBCLKLOST=,
+                                       o_CPLLLOCK=self.cplllock,
+                                       i_CPLLLOCKDETCLK=0,
+                                       i_CPLLLOCKEN=1,
+                                       i_CPLLPD=0,
+                                       #o_CPLLREFCLKLOST=0,
+                                       i_CPLLREFCLKSEL=0b001,
+                                       i_CPLLRESET=self.cpllreset,
+                                       i_GTRSVD=0,
+                                       i_PCSRSVDIN=0,
+                                       i_PCSRSVDIN2=0,
+                                       i_PMARSVDIN=0,
+                                       i_PMARSVDIN2=0,
+                                       i_TSTIN=ones(20),
+                                       #o_TSTOUT=,
+
+                               # Channel
+                                       i_CLKRSVD=0,
+
+                               # Channel - Clocking Ports
+                                       i_GTGREFCLK=0,
+                                       i_GTNORTHREFCLK0=0,
+                                       i_GTNORTHREFCLK1=0,
+                                       i_GTREFCLK0=self.gtrefclk0,
+                                       i_GTREFCLK1=0,
+                                       i_GTSOUTHREFCLK0=0,
+                                       i_GTSOUTHREFCLK1=0,
+
+                               # Channel - DRP Ports
+                                       i_DRPADDR=0,
+                                       i_DRPCLK=0,
+                                       i_DRPDI=0,
+                                       #o_DRPDO=,
+                                       i_DRPEN=0,
+                                       #o_DRPRDY=,
+                                       i_DRPWE=0,
+
+                               # Clocking Ports
+                                       #o_GTREFCLKMONITOR=,
+                                       i_QPLLCLK=self.qpllclk,
+                                       i_QPLLREFCLK=self.qpllrefclk,
+                                       i_RXSYSCLKSEL=0b00,
+                                       i_TXSYSCLKSEL=0b00,
+
+                               # Digital Monitor Ports
+                                       #o_DMONITOROUT=,
+
+                               # FPGA TX Interface Datapath Configuration
+                                       i_TX8B10BEN=1,
+
+                               # Loopback Ports
+                                       i_LOOPBACK=0,
+
+                               # PCI Express Ports
+                                       #o_PHYSTATUS=,
+                                       i_RXRATE=0,
+                                       #o_RXVALID=,
+
+                               # Power-Down Ports
+                                       i_RXPD=0b00,
+                                       i_TXPD=0b00,
+
+                               # RX 8B/10B Decoder Ports
+                                       i_SETERRSTATUS=0,
+
+                               # RX Initialization and Reset Ports
+                                       i_EYESCANRESET=0,
+                                       i_RXUSERRDY=rxuserrdy,
+
+                               # RX Margin Analysis Ports
+                                       #o_EYESCANDATAERROR=,
+                                       i_EYESCANMODE=0,
+                                       i_EYESCANTRIGGER=0,
+
+                               # Receive Ports - CDR Ports
+                                       i_RXCDRFREQRESET=0,
+                                       i_RXCDRHOLD=0,
+                                       o_RXCDRLOCK=rxcdrlock,
+                                       i_RXCDROVRDEN=0,
+                                       i_RXCDRRESET=0,
+                                       i_RXCDRRESETRSV=0,
+
+                               # Receive Ports - Clock Correction Ports
+                                       #o_RXCLKCORCNT=,
+
+                               # Receive Ports - FPGA RX Interface Datapath Configuration
+                                       i_RX8B10BEN=1,
+
+                               # Receive Ports - FPGA RX Interface Ports
+                                       i_RXUSRCLK=self.rxusrclk,
+                                       i_RXUSRCLK2=self.rxusrclk2,
+
+                               # Receive Ports - FPGA RX interface Ports
+                                       o_RXDATA=self.rxdata,
+
+                               # Receive Ports - Pattern Checker Ports
+                                       #o_RXPRBSERR=,
+                                       i_RXPRBSSEL=0,
+
+                               # Receive Ports - Pattern Checker ports
+                                       i_RXPRBSCNTRESET=0,
+
+                               # Receive Ports - RX  Equalizer Ports
+                                       i_RXDFEXYDEN=0,
+                                       i_RXDFEXYDHOLD=0,
+                                       i_RXDFEXYDOVRDEN=0,
+
+                               # Receive Ports - RX 8B/10B Decoder Ports
+                                       #o_RXDISPERR=,
+                                       #o_RXNOTINTABLE=,
+
+                               # Receive Ports - RX AFE
+                                       i_GTXRXP=pads.rxp,
+                                       i_GTXRXN=pads.rxn,
+
+                               # Receive Ports - RX Buffer Bypass Ports
+                                       i_RXBUFRESET=0,
+                                       #o_RXBUFSTATUS=,
+                                       i_RXDDIEN=0,
+                                       i_RXDLYBYPASS=1,
+                                       i_RXDLYEN=0,
+                                       i_RXDLYOVRDEN=0,
+                                       i_RXDLYSRESET=0,
+                                       #o_RXDLYSRESETDONE=0,
+                                       i_RXPHALIGN=0,
+                                       #o_RXPHALIGNDONE=,
+                                       i_RXPHALIGNEN=0,
+                                       i_RXPHDLYPD=0,
+                                       i_RXPHDLYRESET=0,
+                                       #o_RXPHMONITOR=,
+                                       i_RXPHOVRDEN=0,
+                                       #o_RXPHSLIPMONITOR=,
+                                       #o_RXSTATUS=,
+
+                               # Receive Ports - RX Byte and Word Alignment Ports
+                                       o_RXBYTEISALIGNED=self.rxbyteisaligned,
+                                       #o_RXBYTEREALIGN=,
+                                       #o_RXCOMMADET=,
+                                       i_RXCOMMADETEN=1,
+                                       i_RXMCOMMAALIGNEN=1,
+                                       i_RXPCOMMAALIGNEN=1,
+
+                               # Receive Ports - RX Channel Bonding Ports
+                                       #o_RXCHANBONDSEQ=,
+                                       i_RXCHBONDEN=0,
+                                       i_RXCHBONDLEVEL=0,
+                                       i_RXCHBONDMASTER=0,
+                                       #o_RXCHBONDO=,
+                                       i_RXCHBONDSLAVE=0,
+
+                               # Receive Ports - RX Channel Bonding Ports
+                                       #o_RXCHANISALIGNED=,
+                                       #o_RXCHANREALIGN=,
+
+                               # Receive Ports - RX Equalizer Ports
+                                       i_RXDFEAGCHOLD=0,
+                                       i_RXDFEAGCOVRDEN=0,
+                                       i_RXDFECM1EN=0,
+                                       i_RXDFELFHOLD=0,
+                                       i_RXDFELFOVRDEN=1,
+                                       i_RXDFELPMRESET=0,
+                                       i_RXDFETAP2HOLD=0,
+                                       i_RXDFETAP2OVRDEN=0,
+                                       i_RXDFETAP3HOLD=0,
+                                       i_RXDFETAP3OVRDEN=0,
+                                       i_RXDFETAP4HOLD=0,
+                                       i_RXDFETAP4OVRDEN=0,
+                                       i_RXDFETAP5HOLD=0,
+                                       i_RXDFETAP5OVRDEN=0,
+                                       i_RXDFEUTHOLD=0,
+                                       i_RXDFEUTOVRDEN=0,
+                                       i_RXDFEVPHOLD=0,
+                                       i_RXDFEVPOVRDEN=0,
+                                       i_RXDFEVSEN=0,
+                                       i_RXLPMLFKLOVRDEN=0,
+                                       #o_RXMONITOROUT=,
+                                       i_RXMONITORSEL=0b00,
+                                       i_RXOSHOLD=0,
+                                       i_RXOSOVRDEN=0,
+
+                               # Receive Ports - RX Equilizer Ports
+                                       i_RXLPMHFHOLD=0,
+                                       i_RXLPMHFOVRDEN=0,
+                                       i_RXLPMLFHOLD=0,
+
+                               # Receive Ports - RX Fabric ClocK Output Control Ports
+                                       #o_RXRATEDONE=,
+
+                               # Receive Ports - RX Fabric Output Control Ports
+                                       o_RXOUTCLK=self.rxoutclk,
+                                       #o_RXOUTCLKFABRIC=,
+                                       #o_RXOUTCLKPCS=,
+                                       i_RXOUTCLKSEL=0b010,
+
+                               # Receive Ports - RX Gearbox Ports
+                                       #o_RXDATAVALID=,
+                                       #o_RXHEADER=,
+                                       #o_RXHEADERVALID=,
+                                       #o_RXSTARTOFSEQ=,
+
+                               # Receive Ports - RX Gearbox Ports
+                                       i_RXGEARBOXSLIP=0,
+
+                               # Receive Ports - RX Initialization and Reset Ports
+                                       i_GTRXRESET=self.gtrxreset,
+                                       i_RXOOBRESET=0,
+                                       i_RXPCSRESET=0,
+                                       i_RXPMARESET=self.pmarxreset,
+
+                               # Receive Ports - RX Margin Analysis ports
+                                       i_RXLPMEN=0,
+
+                               # Receive Ports - RX OOB Signaling ports
+                                       #o_RXCOMSASDET=,
+                                       o_RXCOMWAKEDET=rxcomwakedet,
+
+                               # Receive Ports - RX OOB Signaling ports
+                                       o_RXCOMINITDET=rxcominitdet,
+
+                               # Receive Ports - RX OOB signalling Ports
+                                       o_RXELECIDLE=rxelecidle,
+                                       i_RXELECIDLEMODE=0b00,
+
+                               # Receive Ports - RX Polarity Control Ports
+                                       i_RXPOLARITY=0,
+
+                               # Receive Ports - RX gearbox ports
+                                       i_RXSLIDE=0,
+
+                               # Receive Ports - RX8B/10B Decoder Ports
+                                       #o_RXCHARISCOMMA=,
+                                       o_RXCHARISK=self.rxcharisk,
+
+                               # Receive Ports - Rx Channel Bonding Ports
+                                       i_RXCHBONDI=0,
+
+                               # Receive Ports -RX Initialization and Reset Ports
+                                       o_RXRESETDONE=rxresetdone,
+
+                               # Rx AFE Ports
+                                       i_RXQPIEN=0,
+                                       #o_RXQPISENN=,
+                                       #o_RXQPISENP=,
+
+                               # TX Buffer Bypass Ports
+                                       i_TXPHDLYTSTCLK=0,
+
+                               # TX Configurable Driver Ports
+                                       i_TXPOSTCURSOR=0,
+                                       i_TXPOSTCURSORINV=0,
+                                       i_TXPRECURSOR=0,
+                                       i_TXPRECURSORINV=0,
+                                       i_TXQPIBIASEN=0,
+                                       i_TXQPISTRONGPDOWN=0,
+                                       i_TXQPIWEAKPUP=0,
+
+                               # TX Initialization and Reset Ports
+                                       i_CFGRESET=0,
+                                       i_GTTXRESET=self.gttxreset,
+                                       #o_PCSRSVDOUT=,
+                                       i_TXUSERRDY=txuserrdy,
+
+                               # Transceiver Reset Mode Operation
+                                       i_GTRESETSEL=0,
+                                       i_RESETOVRD=0,
+
+                               # Transmit Ports - 8b10b Encoder Control Ports
+                                       i_TXCHARDISPMODE=0,
+                                       i_TXCHARDISPVAL=0,
+
+                               # Transmit Ports - FPGA TX Interface Ports
+                                       i_TXUSRCLK=self.txusrclk,
+                                       i_TXUSRCLK2=self.txusrclk2,
+
+                               # Transmit Ports - PCI Express Ports
+                                       i_TXELECIDLE=txelecidle,
+                                       i_TXMARGIN=0,
+                                       i_TXRATE=txrate,
+                                       i_TXSWING=0,
+
+                               # Transmit Ports - Pattern Generator Ports
+                                       i_TXPRBSFORCEERR=0,
+
+                               # Transmit Ports - TX Buffer Bypass Ports
+                                       i_TXDLYBYPASS=1,
+                                       i_TXDLYEN=0,
+                                       i_TXDLYHOLD=0,
+                                       i_TXDLYOVRDEN=0,
+                                       i_TXDLYSRESET=0,
+                                       #o_TXDLYSRESETDONE=,
+                                       i_TXDLYUPDOWN=0,
+                                       i_TXPHALIGN=0,
+                                       #o_TXPHALIGNDONE=txphaligndone,
+                                       i_TXPHALIGNEN=0,
+                                       i_TXPHDLYPD=0,
+                                       i_TXPHDLYRESET=0,
+                                       i_TXPHINIT=0,
+                                       #o_TXPHINITDONE=,
+                                       i_TXPHOVRDEN=0,
+
+                               # Transmit Ports - TX Buffer Ports
+                                       #o_TXBUFSTATUS=,
+
+                               # Transmit Ports - TX Configurable Driver Ports
+                                       i_TXBUFDIFFCTRL=0b100,
+                                       i_TXDEEMPH=0,
+                                       i_TXDIFFCTRL=0b1000,
+                                       i_TXDIFFPD=0,
+                                       i_TXINHIBIT=0,
+                                       i_TXMAINCURSOR=0,
+                                       i_TXPISOPD=0,
+
+                               # Transmit Ports - TX Data Path interface
+                                       i_TXDATA=self.txdata,
+
+                               # Transmit Ports - TX Driver and OOB signaling
+                                       o_GTXTXP=pads.txp,
+                                       o_GTXTXN=pads.txn,
+
+                               # Transmit Ports - TX Fabric Clock Output Control Ports
+                                       o_TXOUTCLK=self.txoutclk,
+                                       #o_TXOUTCLKFABRIC=,
+                                       #o_TXOUTCLKPCS=,
+                                       i_TXOUTCLKSEL=0b11, #??
+                                       #o_TXRATEDONE=,
+                               # Transmit Ports - TX Gearbox Ports
+                                       i_TXCHARISK=self.txcharisk,
+                                       #o_TXGEARBOXREADY=,
+                                       i_TXHEADER=0,
+                                       i_TXSEQUENCE=0,
+                                       i_TXSTARTSEQ=0,
+
+                               # Transmit Ports - TX Initialization and Reset Ports
+                                       i_TXPCSRESET=0,
+                                       i_TXPMARESET=0,
+                                       o_TXRESETDONE=txresetdone,
+
+                               # Transmit Ports - TX OOB signalling Ports
+                                       o_TXCOMFINISH=txcomfinish,
+                                       i_TXCOMINIT=txcominit,
+                                       i_TXCOMSAS=0,
+                                       i_TXCOMWAKE=txcomwake,
+                                       i_TXPDELECIDLEMODE=0,
+
+                               # Transmit Ports - TX Polarity Control Ports
+                                       i_TXPOLARITY=0,
+
+                               # Transmit Ports - TX Receiver Detection Ports
+                                       i_TXDETECTRX=0,
+
+                               # Transmit Ports - TX8b/10b Encoder Ports
+                                       i_TX8B10BBYPASS=0,
+
+                               # Transmit Ports - pattern Generator Ports
+                                       i_TXPRBSSEL=0,
+
+                               # Tx Configurable Driver  Ports
+                                       #o_TXQPISENN=,
+                                       #o_TXQPISENP=,
+
+                                       **gtxe2_channel_parameters
+                       )
diff --git a/litesata/test/Makefile b/litesata/test/Makefile
new file mode 100644 (file)
index 0000000..6b2723b
--- /dev/null
@@ -0,0 +1,33 @@
+MSCDIR = ../../
+PYTHON = python3
+
+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
+
+scrambler_tb:
+       $(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
+       $(CMD) scrambler_tb.py
+
+cont_tb:
+       $(CMD) cont_tb.py
+
+link_tb:
+       $(CMD) link_tb.py
+
+command_tb:
+       $(CMD) command_tb.py
+
+bist_tb:
+       $(CMD) bist_tb.py
+
+clean:
+       rm crc scrambler *.vcd
diff --git a/litesata/test/bist_tb.py b/litesata/test/bist_tb.py
new file mode 100644 (file)
index 0000000..ed83750
--- /dev/null
@@ -0,0 +1,45 @@
+from litesata.common import *
+from litesata import LiteSATA
+from litesata.frontend.bist import LiteSATABISTGenerator, LiteSATABISTChecker
+
+from litesata.test.hdd import *
+from litesata.test.common import *
+
+class TB(Module):
+       def __init__(self):
+               self.hdd = HDD(
+                               link_debug=False, link_random_level=0,
+                               transport_debug=False, transport_loopback=False,
+                               hdd_debug=True)
+               self.controller = LiteSATA(self.hdd.phy, with_crossbar=True)
+               self.generator = LiteSATABISTGenerator(self.controller.crossbar.get_port())
+               self.checker = LiteSATABISTChecker(self.controller.crossbar.get_port())
+
+       def gen_simulation(self, selfp):
+               hdd = self.hdd
+               hdd.malloc(0, 64)
+               selfp.generator.sector = 0
+               selfp.generator.count = 17
+               selfp.checker.sector = 0
+               selfp.checker.count = 17
+               while True:
+                       selfp.generator.start = 1
+                       yield
+                       selfp.generator.start = 0
+                       yield
+                       while selfp.generator.done == 0:
+                               yield
+                       selfp.checker.start = 1
+                       yield
+                       selfp.checker.start = 0
+                       yield
+                       while selfp.checker.done == 0:
+                               yield
+                       print("errors {}".format(selfp.checker.errors))
+                       selfp.generator.sector += 1
+                       selfp.generator.count = max((selfp.generator.count + 1)%8, 1)
+                       selfp.checker.sector += 1
+                       selfp.checker.count = max((selfp.checker.count + 1)%8, 1)
+
+if __name__ == "__main__":
+       run_simulation(TB(), ncycles=8192*2, vcd_name="my.vcd", keep_files=True)
diff --git a/litesata/test/command_tb.py b/litesata/test/command_tb.py
new file mode 100644 (file)
index 0000000..b5c9dc4
--- /dev/null
@@ -0,0 +1,96 @@
+from litesata.common import *
+from litesata.core import LiteSATACore
+
+from litesata.test.hdd import *
+from litesata.test.common import *
+
+class CommandTXPacket(list):
+       def __init__(self, write=0, read=0, sector=0, count=0, data=[]):
+               self.ongoing = False
+               self.done = False
+               self.write = write
+               self.read = read
+               self.sector = sector
+               self.count = count
+               for d in data:
+                       self.append(d)
+
+class CommandStreamer(PacketStreamer):
+       def __init__(self):
+               PacketStreamer.__init__(self, command_tx_description(32), CommandTXPacket)
+
+       def do_simulation(self, selfp):
+               PacketStreamer.do_simulation(self, selfp)
+               selfp.source.write = self.packet.write
+               selfp.source.read = self.packet.read
+               selfp.source.sector = self.packet.sector
+               selfp.source.count = self.packet.count
+
+class CommandRXPacket(list):
+       def __init__(self):
+               self.ongoing = False
+               self.done = False
+               self.write = 0
+               self.read = 0
+               self.success = 0
+               self.failed = 0
+
+class CommandLogger(PacketLogger):
+       def __init__(self):
+               PacketLogger.__init__(self, command_rx_description(32), CommandRXPacket)
+
+       def do_simulation(self, selfp):
+               selfp.sink.ack = 1
+               if selfp.sink.stb == 1 and selfp.sink.sop == 1:
+                       self.packet = CommandRXPacket()
+                       self.packet.write = selfp.sink.write
+                       self.packet.read = selfp.sink.read
+                       self.packet.sucess = selfp.sink.success
+                       self.packet.failed = selfp.sink.failed
+                       self.packet.append(selfp.sink.data)
+               elif selfp.sink.stb:
+                       self.packet.append(selfp.sink.data)
+               if selfp.sink.stb == 1 and selfp.sink.eop == 1:
+                       self.packet.done = True
+
+class TB(Module):
+       def __init__(self):
+               self.hdd = HDD(
+                               link_debug=False, link_random_level=50,
+                               transport_debug=False, transport_loopback=False,
+                               hdd_debug=True)
+               self.core = LiteSATACore(self.hdd.phy)
+
+               self.streamer = CommandStreamer()
+               self.streamer_randomizer = Randomizer(command_tx_description(32), level=50)
+
+               self.logger = CommandLogger()
+               self.logger_randomizer = Randomizer(command_rx_description(32), level=50)
+
+               self.pipeline = Pipeline(
+                       self.streamer,
+                       self.streamer_randomizer,
+                       self.core,
+                       self.logger_randomizer,
+                       self.logger
+               )
+
+       def gen_simulation(self, selfp):
+               hdd = self.hdd
+               hdd.malloc(0, 64)
+               write_data = [i for i in range(sectors2dwords(2))]
+               write_len = dwords2sectors(len(write_data))
+               write_packet = CommandTXPacket(write=1, sector=2, count=write_len, data=write_data)
+               yield from self.streamer.send(write_packet)
+               yield from self.logger.receive()
+               read_packet = CommandTXPacket(read=1, sector=2, count=write_len)
+               yield from self.streamer.send(read_packet)
+               yield from self.logger.receive()
+               read_data = self.logger.packet
+
+               # check results
+               s, l, e = check(write_data, read_data)
+               print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+if __name__ == "__main__":
+       run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
diff --git a/litesata/test/common.py b/litesata/test/common.py
new file mode 100644 (file)
index 0000000..ec8da98
--- /dev/null
@@ -0,0 +1,135 @@
+import random, copy
+
+from migen.sim.generic import run_simulation
+
+from litesata.common import *
+
+def seed_to_data(seed, random=True):
+       if random:
+               return (seed * 0x31415979 + 1) & 0xffffffff
+       else:
+               return seed
+
+def check(p1, p2):
+       p1 = copy.deepcopy(p1)
+       p2 = copy.deepcopy(p2)
+       if isinstance(p1, int):
+               return 0, 1, int(p1 != p2)
+       else:
+               if len(p1) >= len(p2):
+                       ref, res = p1, p2
+               else:
+                       ref, res = p2, p1
+               shift = 0
+               while((ref[0] != res[0]) and (len(res)>1)):
+                       res.pop(0)
+                       shift += 1
+               length = min(len(ref), len(res))
+               errors = 0
+               for i in range(length):
+                       if ref.pop(0) != res.pop(0):
+                               errors += 1
+               return shift, length, errors
+
+def randn(max_n):
+       return random.randint(0, max_n-1)
+
+class PacketStreamer(Module):
+       def __init__(self, description, packet_class):
+               self.source = Source(description)
+               ###
+               self.packets = []
+               self.packet = packet_class()
+               self.packet.done = 1
+
+               self.source_data = 0
+
+       def send(self, packet, blocking=True):
+               packet = copy.deepcopy(packet)
+               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 not self.packet.ongoing and not self.packet.done:
+                       selfp.source.stb = 1
+                       if self.source.description.packetized:
+                               selfp.source.sop = 1
+                       if len(self.packet) > 0:
+                               self.source_data = self.packet.pop(0)
+                               if hasattr(selfp.source, "data"):
+                                       selfp.source.data = self.source_data
+                               else:
+                                       selfp.source.d = self.source_data
+                       self.packet.ongoing = True
+               elif selfp.source.stb == 1 and selfp.source.ack == 1:
+                       if self.source.description.packetized:
+                               selfp.source.sop = 0
+                               selfp.source.eop = (len(self.packet) == 1)
+                       if len(self.packet) > 0:
+                               selfp.source.stb = 1
+                               self.source_data = self.packet.pop(0)
+                               if hasattr(selfp.source, "data"):
+                                       selfp.source.data = self.source_data
+                               else:
+                                       selfp.source.d = self.source_data
+                       else:
+                               self.packet.done = 1
+                               selfp.source.stb = 0
+
+class PacketLogger(Module):
+       def __init__(self, description, packet_class):
+               self.sink = Sink(description)
+               ###
+               self.packet_class = packet_class
+               self.packet = packet_class()
+
+       def receive(self, length=None):
+               self.packet.done = 0
+               if length is None:
+                       while self.packet.done == 0:
+                               yield
+               else:
+                       while length > len(self.packet):
+                               yield
+
+       def do_simulation(self, selfp):
+               selfp.sink.ack = 1
+               if self.sink.description.packetized:
+                       if selfp.sink.stb == 1 and selfp.sink.sop == 1:
+                               self.packet = self.packet_class()
+               if selfp.sink.stb:
+                       if hasattr(selfp.sink, "data"):
+                               self.packet.append(selfp.sink.data)
+                       else:
+                               self.packet.append(selfp.sink.d)
+               if self.sink.description.packetized:
+                       if selfp.sink.stb == 1 and selfp.sink.eop == 1:
+                               self.packet.done = True
+
+class Randomizer(Module):
+       def __init__(self, description, level=0):
+               self.level = level
+
+               self.sink = Sink(description)
+               self.source = Source(description)
+
+               self.run = Signal()
+
+               self.comb += \
+                       If(self.run,
+                               Record.connect(self.sink, self.source)
+                       ).Else(
+                               self.source.stb.eq(0),
+                               self.sink.ack.eq(0),
+                       )
+
+       def do_simulation(self, selfp):
+               n = randn(100)
+               if n < self.level:
+                       selfp.run = 0
+               else:
+                       selfp.run = 1
diff --git a/litesata/test/cont_tb.py b/litesata/test/cont_tb.py
new file mode 100644 (file)
index 0000000..bbd6901
--- /dev/null
@@ -0,0 +1,95 @@
+from litesata.common import *
+from litesata.core.link.cont import LiteSATACONTInserter, LiteSATACONTRemover
+
+from litesata.test.common import *
+
+class ContPacket(list):
+       def __init__(self, data=[]):
+               self.ongoing = False
+               self.done = False
+               for d in data:
+                       self.append(d)
+
+class ContStreamer(PacketStreamer):
+       def __init__(self):
+               PacketStreamer.__init__(self, phy_description(32), ContPacket)
+
+       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 ContLogger(PacketLogger):
+       def __init__(self):
+               PacketLogger.__init__(self, phy_description(32), ContPacket)
+
+class TB(Module):
+       def __init__(self):
+               self.streamer = ContStreamer()
+               self.streamer_randomizer = Randomizer(phy_description(32), level=50)
+               self.inserter = LiteSATACONTInserter(phy_description(32))
+               self.remover = LiteSATACONTRemover(phy_description(32))
+               self.logger_randomizer = Randomizer(phy_description(32), level=50)
+               self.logger = ContLogger()
+
+               self.pipeline = Pipeline(
+                       self.streamer,
+                       self.streamer_randomizer,
+                       self.inserter,
+                       self.remover,
+                       self.logger_randomizer,
+                       self.logger
+               )
+
+       def gen_simulation(self, selfp):
+               test_packet = ContPacket([
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["ALIGN"],
+                       primitives["ALIGN"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       #primitives["SYNC"],
+                       0x00000000,
+                       0x00000001,
+                       0x00000002,
+                       0x00000003,
+                       0x00000004,
+                       0x00000005,
+                       0x00000006,
+                       0x00000007,
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["ALIGN"],
+                       primitives["ALIGN"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["SYNC"],
+                       primitives["SYNC"]]*4
+                       )
+               streamer_packet = ContPacket(test_packet)
+               yield from self.streamer.send(streamer_packet)
+               yield from self.logger.receive(len(test_packet))
+               #for d in self.logger.packet:
+               #       print("%08x" %d)
+
+               # 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=1024, vcd_name="my.vcd", keep_files=True)
diff --git a/litesata/test/crc.c b/litesata/test/crc.c
new file mode 100644 (file)
index 0000000..75576b5
--- /dev/null
@@ -0,0 +1,149 @@
+// Adapted from SATA specification
+/****************************************************************************/
+/*                                                                          */
+/* crc.c                                                                    */
+/*                                                                          */
+/* This sample code reads standard in for a sequence of 32 bit values       */
+/* formatted in hexadecimal with a leading "0x" (e.g. 0xDEADBEEF). The      */
+/* code calculates the Serial ATA CRC for the input data stream. The        */
+/* generator polynomial used is:                                            */
+/* 32 26 23 22 16 12 11 10 8 7 5 4 2                                        */
+/* G(x) = x + x + x + x + x + x + x + x + x + x + x + x + x + x + 1         */
+/*                                                                          */
+/* This sample code uses a parallel implementation of the CRC calculation   */
+/* circuit that is suitable for implementation in hardware. A block         */
+/* diagram of the circuit being emulated is shown below.                    */
+/*                                                                          */
+/*                   +---+          +---+          +---+                    */
+/* Data_In --------->|   |          |   |          | R |                    */
+/*                   | + |--------->| * |--------->| e |----+               */
+/*             +---->|   |          |   |          | g |    |               */
+/*             |     +---+          +---+          +---+    |               */
+/*             |                                            |               */
+/*             |                                            |               */
+/*             +--------------------------------------------+               */
+/*                                                                          */
+/* The CRC value is initialized to 0x52325032 as defined in the Serial ATA  */
+/* specification.                                                           */
+/*                                                                          */
+/****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <stdio.h>
+int main(int argc, char *argv[])
+{
+   int i;
+   unsigned int data_count;
+   unsigned int crc;
+   unsigned int data_in;
+   unsigned char crc_bit[32];
+   unsigned char new_bit[32];
+
+   crc = 0x52325032;
+   data_count = 0;
+
+   while((scanf(" 0x%8x", &data_in) == 1) && (!scanf("exit"))) {
+      data_count++;
+      /* Add the data_in value to the current value of the CRC held in the  */
+      /* "register". The addition is performed modulo two (XOR).            */
+      crc ^= data_in;
+      /* Expand the value of the CRC held in the register to 32 individual  */
+      /* bits for easy manipulation. */
+      for (i = 0; i < 32; ++i)  {
+         crc_bit[i] = (crc >> i) & 0x01;
+      }
+      /* The following 32 assignments perform the function of the box       */
+      /* labeled "*" in the block diagram above. The new_bit array is a     */
+      /* temporary holding place for the new CRC value being calculated.    */
+      /* Note that there are lots of shared terms in the assignments below. */
+      new_bit[31] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^
+                    crc_bit[23] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[5];
+      new_bit[30] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^
+                    crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[4];
+      new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^
+                    crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[3];
+      new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^
+                    crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[2];
+      new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^
+                    crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[1];
+      new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^
+                    crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6]  ^ crc_bit[4]  ^ crc_bit[3]  ^
+                    crc_bit[0];
+      new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^
+                    crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8]  ^ crc_bit[3]  ^ crc_bit[2];
+      new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^
+                    crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7]  ^ crc_bit[2]  ^ crc_bit[1];
+      new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^
+                    crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9]  ^ crc_bit[6]  ^ crc_bit[1]  ^ crc_bit[0];
+      new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^
+                    crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9]  ^ crc_bit[0];
+      new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^
+                    crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9]  ^ crc_bit[5];
+      new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^
+                    crc_bit[16] ^ crc_bit[12] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[4];
+      new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^
+                    crc_bit[15] ^ crc_bit[11] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[3];
+      new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^
+                    crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[2];
+      new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^
+                    crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[1];
+      new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^
+                    crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[0];
+      new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^
+                    crc_bit[15] ^ crc_bit[12] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[5]  ^ crc_bit[4]  ^
+                    crc_bit[3];
+      new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^
+                    crc_bit[14] ^ crc_bit[11] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[4]  ^ crc_bit[3]  ^
+                    crc_bit[2];
+      new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^
+                    crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[3]  ^
+                    crc_bit[2]  ^ crc_bit[1];
+      new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^
+                    crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[4]  ^
+                    crc_bit[2]  ^ crc_bit[1]  ^ crc_bit[0];
+      new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^
+                    crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9]  ^ crc_bit[4]  ^
+                    crc_bit[3]  ^ crc_bit[1]  ^ crc_bit[0];
+      new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^
+                    crc_bit[13] ^ crc_bit[9]  ^ crc_bit[5]  ^ crc_bit[3]  ^ crc_bit[2]  ^ crc_bit[0];
+      new_bit[9]  = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^
+                    crc_bit[9]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[2]  ^ crc_bit[1];
+      new_bit[8]  = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^
+                    crc_bit[10] ^ crc_bit[8]  ^ crc_bit[4]  ^ crc_bit[3]  ^ crc_bit[1]  ^ crc_bit[0];
+      new_bit[7]  = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^
+                    crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[5]  ^ crc_bit[3]  ^
+                    crc_bit[2]  ^ crc_bit[0];
+      new_bit[6]  = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^
+                    crc_bit[11] ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[2]  ^
+                    crc_bit[1];
+      new_bit[5]  = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^
+                    crc_bit[10] ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[5]  ^ crc_bit[4]  ^ crc_bit[3]  ^ crc_bit[1]  ^
+                    crc_bit[0];
+      new_bit[4]  = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^
+                    crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8]  ^ crc_bit[6]  ^ crc_bit[4]  ^
+                    crc_bit[3]  ^ crc_bit[2]  ^ crc_bit[0];
+      new_bit[3]  = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^
+                    crc_bit[14] ^ crc_bit[10] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[3]  ^ crc_bit[2]  ^
+                    crc_bit[1];
+      new_bit[2]  = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^
+                    crc_bit[14] ^ crc_bit[13] ^ crc_bit[9]  ^ crc_bit[8]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[2]  ^
+                    crc_bit[1]  ^ crc_bit[0];
+      new_bit[1]  = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^
+                    crc_bit[11] ^ crc_bit[9]  ^ crc_bit[7]  ^ crc_bit[6]  ^ crc_bit[1]  ^ crc_bit[0];
+      new_bit[0]  = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^
+                    crc_bit[16] ^ crc_bit[12] ^ crc_bit[10] ^ crc_bit[9]  ^ crc_bit[6]  ^ crc_bit[0];
+
+      /* The new CRC value has been calculated as individual bits in the */
+      /* new_bit array. Re-assembled it into a 32 bit value and "clock" it */
+      /* into the "register". */
+      crc = 0;
+      for (i = 31; i >= 0; --i)  {
+         crc = crc << 1;
+         crc |= new_bit[i];
+      }
+   }
+   printf("%08x\n", crc);
+   return 0;
+}
diff --git a/litesata/test/crc_tb.py b/litesata/test/crc_tb.py
new file mode 100644 (file)
index 0000000..a36ec83
--- /dev/null
@@ -0,0 +1,59 @@
+import subprocess
+
+from litesata.common import *
+from litesata.core.link.crc import *
+
+from litesata.test.common import *
+
+class TB(Module):
+       def __init__(self, length, random):
+               self.crc = LiteSATACRC()
+               self.length = length
+               self.random = random
+
+       def get_c_crc(self, datas):
+               stdin = ""
+               for data in datas:
+                       stdin += "0x%08x " %data
+               stdin += "exit"
+               with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+                       process.stdin.write(stdin.encode("ASCII"))
+                       out, err = process.communicate()
+               return int(out.decode("ASCII"), 16)
+
+       def gen_simulation(self, selfp):
+               # init CRC
+               selfp.crc.d = 0
+               selfp.crc.ce = 1
+               selfp.crc.reset = 1
+               yield
+               selfp.crc.reset = 0
+
+               # feed CRC with datas
+               datas = []
+               for i in range(self.length):
+                       data = seed_to_data(i, self.random)
+                       datas.append(data)
+                       selfp.crc.d = data
+                       yield
+
+               # log results
+               yield
+               sim_crc = selfp.crc.value
+
+               # stop
+               selfp.crc.ce = 0
+               for i in range(32):
+                       yield
+
+               # get C core reference
+               c_crc = self.get_c_crc(datas)
+
+               # check results
+               s, l, e = check(c_crc, sim_crc)
+               print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+if __name__ == "__main__":
+       from migen.sim.generic import run_simulation
+       length = 8192
+       run_simulation(TB(length, True), ncycles=length+100, vcd_name="my.vcd")
diff --git a/litesata/test/hdd.py b/litesata/test/hdd.py
new file mode 100644 (file)
index 0000000..6e897f8
--- /dev/null
@@ -0,0 +1,511 @@
+import subprocess
+import math
+
+from litesata.common import *
+from litesata.test.common import *
+
+def print_with_prefix(s, prefix=""):
+       if not isinstance(s, str):
+               s = s.__repr__()
+       s = s.split("\n")
+       for l in s:
+               print(prefix + l)
+
+# PHY Layer model
+class PHYDword:
+       def __init__(self, dat=0):
+               self.dat = dat
+               self.start = 1
+               self.done = 0
+
+class PHYSource(Module):
+       def __init__(self):
+               self.source = Source(phy_description(32))
+               ###
+               self.dword = PHYDword()
+
+       def send(self, dword):
+               self.dword = dword
+
+       def do_simulation(self, selfp):
+               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
+
+class PHYSink(Module):
+       def __init__(self):
+               self.sink = Sink(phy_description(32))
+               ###
+               self.dword = PHYDword()
+
+       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 PHYLayer(Module):
+       def __init__(self):
+
+               self.rx = PHYSink()
+               self.tx = PHYSource()
+
+               self.source = self.tx.source
+               self.sink = self.rx.sink
+
+       def send(self, dword):
+               packet = PHYDword(dword)
+               self.tx.send(packet)
+
+       def receive(self):
+               yield from self.rx.receive()
+
+       def __repr__(self):
+               receiving = "%08x " %self.rx.dword.dat
+               receiving += decode_primitive(self.rx.dword.dat)
+               receiving += " "*(16-len(receiving))
+
+               sending = "%08x " %self.tx.dword.dat
+               sending += decode_primitive(self.tx.dword.dat)
+               sending += " "*(16-len(sending))
+
+               return receiving + sending
+
+# Link Layer model
+def print_link(s):
+       print_with_prefix(s, "[LNK]: ")
+
+def import_scrambler_datas():
+       with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+               process.stdin.write("0x10000".encode("ASCII"))
+               out, err = process.communicate()
+       return [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]]
+
+class LinkPacket(list):
+       def __init__(self, init=[]):
+               self.ongoing = False
+               self.done = False
+               self.scrambled_datas = import_scrambler_datas()
+               for dword in init:
+                       self.append(dword)
+
+class LinkRXPacket(LinkPacket):
+       def descramble(self):
+               for i in range(len(self)):
+                       self[i] = self[i] ^ self.scrambled_datas[i]
+
+       def check_crc(self):
+               stdin = ""
+               for v in self[:-1]:
+                       stdin += "0x%08x " %v
+               stdin += "exit"
+               with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+                       process.stdin.write(stdin.encode("ASCII"))
+                       out, err = process.communicate()
+               crc = int(out.decode("ASCII"), 16)
+               r = (self[-1] == crc)
+               self.pop()
+               return r
+
+       def decode(self):
+               self.descramble()
+               return self.check_crc()
+
+class LinkTXPacket(LinkPacket):
+       def insert_crc(self):
+               stdin = ""
+               for v in self:
+                       stdin += "0x%08x " %v
+               stdin += "exit"
+               with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+                       process.stdin.write(stdin.encode("ASCII"))
+                       out, err = process.communicate()
+               crc = int(out.decode("ASCII"), 16)
+               self.append(crc)
+
+       def scramble(self):
+               for i in range(len(self)):
+                       self[i] = self[i] ^ self.scrambled_datas[i]
+
+       def encode(self):
+               self.insert_crc()
+               self.scramble()
+
+class LinkLayer(Module):
+       def  __init__(self, phy, debug=False, random_level=0):
+               self.phy = phy
+               self.debug = debug
+               self.random_level = random_level
+               self.tx_packets = []
+               self.tx_packet = LinkTXPacket()
+               self.rx_packet = LinkRXPacket()
+
+               self.rx_cont = False
+               self.rx_last = 0
+               self.tx_cont = False
+               self.tx_cont_nb = -1
+               self.tx_lasts = [0, 0, 0]
+
+               self.scrambled_datas = import_scrambler_datas()
+
+               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
+
+       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":
+                       if dword == primitives["HOLD"]:
+                               self.phy.send(primitives["HOLDA"])
+                       else:
+                               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
+                       if self.tx_packet.done:
+                               self.phy.send(primitives["SYNC"])
+
+       def insert_cont(self):
+               self.tx_lasts.pop(0)
+               self.tx_lasts.append(self.phy.tx.dword.dat)
+               self.tx_cont = True
+               for i in range(3):
+                       if not is_primitive(self.tx_lasts[i]):
+                               self.tx_cont = False
+                       if self.tx_lasts[i] != self.tx_lasts[0]:
+                               self.tx_cont = False
+               if self.tx_cont:
+                       if self.tx_cont_nb == 0:
+                               self.phy.send(primitives["CONT"])
+                       else:
+                               self.phy.send(self.scrambled_datas[self.tx_cont_nb])
+                       self.tx_cont_nb += 1
+               else:
+                       self.tx_cont_nb = 0
+
+       def remove_cont(self, dword):
+               if dword == primitives["HOLD"]:
+                       if self.rx_cont:
+                               self.tx_lasts = [0, 0, 0]
+               if dword == primitives["CONT"]:
+                       self.rx_cont = True
+               elif is_primitive(dword):
+                       self.rx_last = dword
+                       self.rx_cont = False
+               if self.rx_cont:
+                       dword = self.rx_last
+               return dword
+
+       def callback(self, dword):
+               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"]:
+                       pass
+               elif self.rx_packet.ongoing:
+                       if dword != primitives["HOLD"]:
+                               n = randn(100)
+                               if n < self.random_level:
+                                       self.phy.send(primitives["HOLD"])
+                               else:
+                                       self.phy.send(primitives["R_IP"])
+                               if not is_primitive(dword):
+                                               self.rx_packet.append(dword)
+               elif dword == primitives["SOF"]:
+                       self.rx_packet = LinkRXPacket()
+                       self.rx_packet.ongoing = True
+
+       def gen_simulation(self, selfp):
+               self.tx_packet.done = True
+               self.phy.send(primitives["SYNC"])
+               while True:
+                       yield from self.phy.receive()
+                       if self.debug:
+                               print_link(self.phy)
+                       self.phy.send(primitives["SYNC"])
+                       rx_dword = self.phy.rx.dword.dat
+                       rx_dword = self.remove_cont(rx_dword)
+                       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(rx_dword)
+                       self.insert_cont()
+
+# Transport Layer model
+def print_transport(s):
+       print_with_prefix(s, "[TRN]: ")
+
+def get_field_data(field, packet):
+       return (packet[field.dword] >> field.offset) & (2**field.width-1)
+
+class FIS:
+       def __init__(self, packet, description, direction="H2D"):
+               self.packet = packet
+               self.description = description
+               self.direction = direction
+               self.decode()
+
+       def decode(self):
+               for k, v in self.description.items():
+                       setattr(self, k, get_field_data(v, self.packet))
+
+       def encode(self):
+               for k, v in self.description.items():
+                       self.packet[v.dword] |= (getattr(self, k) << v.offset)
+
+       def __repr__(self):
+               if self.direction == "H2D":
+                       r = ">>>>>>>>\n"
+               else:
+                       r = "<<<<<<<<\n"
+               for k in sorted(self.description.keys()):
+                       r += k + " : 0x%x" %getattr(self,k) + "\n"
+               return r
+
+class FIS_REG_H2D(FIS):
+       def __init__(self, packet=[0]*fis_reg_h2d_cmd_len):
+               FIS.__init__(self, packet, fis_reg_h2d_layout)
+               self.type = fis_types["REG_H2D"]
+               self.direction = "H2D"
+
+       def __repr__(self):
+               r = "FIS_REG_H2D\n"
+               r += FIS.__repr__(self)
+               return r
+
+class FIS_REG_D2H(FIS):
+       def __init__(self, packet=[0]*fis_reg_d2h_cmd_len):
+               FIS.__init__(self, packet, fis_reg_d2h_layout)
+               self.type = fis_types["REG_D2H"]
+               self.direction = "D2H"
+
+       def __repr__(self):
+               r = "FIS_REG_D2H\n"
+               r += FIS.__repr__(self)
+               return r
+
+class FIS_DMA_ACTIVATE_D2H(FIS):
+       def __init__(self, packet=[0]*fis_dma_activate_d2h_cmd_len):
+               FIS.__init__(self, packet, fis_dma_activate_d2h_layout)
+               self.type = fis_types["DMA_ACTIVATE_D2H"]
+               self.direction = "D2H"
+
+       def __repr__(self):
+               r = "FIS_DMA_ACTIVATE_D2H\n"
+               r += FIS.__repr__(self)
+               return r
+
+class FIS_DATA(FIS):
+       def __init__(self, packet=[0], direction="H2D"):
+               FIS.__init__(self, packet, fis_data_layout, direction)
+               self.type = fis_types["DATA"]
+
+       def __repr__(self):
+               r = "FIS_DATA\n"
+               r += FIS.__repr__(self)
+               for data in self.packet[1:]:
+                       r += "%08x\n" %data
+               return r
+
+class FIS_UNKNOWN(FIS):
+       def __init__(self, packet=[0], direction="H2D"):
+               FIS.__init__(self, packet, {}, direction)
+
+       def __repr__(self):
+               r = "UNKNOWN\n"
+               if self.direction == "H2D":
+                       r += ">>>>>>>>\n"
+               else:
+                       r += "<<<<<<<<\n"
+               for dword in self.packet:
+                       r += "%08x\n" %dword
+               return r
+
+class TransportLayer(Module):
+       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 set_command_callback(self, callback):
+               self.command_callback = callback
+
+       def send(self, fis):
+               fis.encode()
+               packet = LinkTXPacket(fis.packet)
+               self.link.tx_packets.append(packet)
+               if self.debug and not self.loopback:
+                       print_transport(fis)
+
+       def callback(self, packet):
+               fis_type = packet[0] & 0xff
+               if fis_type == fis_types["REG_H2D"]:
+                       fis = FIS_REG_H2D(packet)
+               elif fis_type == fis_types["REG_D2H"]:
+                       fis = FIS_REG_D2H(packet)
+               elif fis_type == fis_types["DMA_ACTIVATE_D2H"]:
+                       fis = FIS_DMA_ACTIVATE_D2H(packet)
+               elif fis_type == fis_types["DATA"]:
+                       fis = FIS_DATA(packet, direction="H2D")
+               else:
+                       fis = FIS_UNKNOWN(packet, direction="H2D")
+               if self.debug:
+                       print_transport(fis)
+               if self.loopback:
+                       self.send(fis)
+               else:
+                       self.command_callback(fis)
+
+# Command Layer model
+class CommandLayer(Module):
+       def __init__(self, transport):
+               self.transport = transport
+               self.transport.set_command_callback(self.callback)
+
+               self.hdd = None
+
+       def set_hdd(self, hdd):
+               self.hdd = hdd
+
+       def callback(self, fis):
+               resp = None
+               if isinstance(fis, FIS_REG_H2D):
+                       if fis.command == regs["WRITE_DMA_EXT"]:
+                               resp =  self.hdd.write_dma_callback(fis)
+                       elif fis.command == regs["READ_DMA_EXT"]:
+                               resp = self.hdd.read_dma_callback(fis)
+               elif isinstance(fis, FIS_DATA):
+                       resp = self.hdd.data_callback(fis)
+
+               if resp is not None:
+                       for packet in resp:
+                               self.transport.send(packet)
+
+# HDD model
+def print_hdd(s):
+       print_with_prefix(s, "[HDD]: ")
+
+class HDDMemRegion:
+       def __init__(self, base, count, sector_size):
+               self.base = base
+               self.count = count
+               self.data = [0]*(count*sector_size//4)
+
+class HDD(Module):
+       def __init__(self,
+                       link_debug=False, link_random_level=0,
+                       transport_debug=False, transport_loopback=False,
+                       hdd_debug=False,
+                       ):
+               ###
+               self.phy = PHYLayer()
+               self.link = LinkLayer(self.phy, link_debug, link_random_level)
+               self.transport = TransportLayer(self.link, transport_debug, transport_loopback)
+               self.command = CommandLayer(self.transport)
+
+               self.command.set_hdd(self)
+
+               self.debug = hdd_debug
+               self.mem = None
+               self.wr_sector = 0
+               self.wr_end_sector = 0
+               self.rd_sector = 0
+               self.rx_end_sector = 0
+
+       def malloc(self, sector, count):
+               if self.debug:
+                       s = "Allocating {n} sectors: {s} to {e}".format(n=count, s=sector, e=sector+count)
+                       s += " ({} KB)".format(count*logical_sector_size//1024)
+                       print_hdd(s)
+               self.mem = HDDMemRegion(sector, count, logical_sector_size)
+
+       def write(self, sector, data):
+               n = math.ceil(dwords2sectors(len(data)))
+               if self.debug:
+                       if n == 1:
+                               s = "{}".format(sector)
+                       else:
+                               s = "{s} to {e}".format(s=sector, e=sector+n-1)
+                       print_hdd("Writing sector " + s)
+               for i in range(len(data)):
+                       offset = sectors2dwords(sector)
+                       self.mem.data[offset+i] = data[i]
+
+       def read(self, sector, count):
+               if self.debug:
+                       if count == 1:
+                               s = "{}".format(sector)
+                       else:
+                               s = "{s} to {e}".format(s=sector, e=sector+count-1)
+                       print_hdd("Reading sector " + s)
+               data = []
+               for i in range(sectors2dwords(count)):
+                       data.append(self.mem.data[sectors2dwords(sector)+i])
+               return data
+
+       def write_dma_callback(self, fis):
+               self.wr_sector = fis.lba_lsb + (fis.lba_msb << 32)
+               self.wr_end_sector = self.wr_sector + fis.count
+               return [FIS_DMA_ACTIVATE_D2H()]
+
+       def read_dma_callback(self, fis):
+               self.rd_sector = fis.lba_lsb + (fis.lba_msb << 32)
+               self.rd_end_sector = self.rd_sector + fis.count
+               packets = []
+               while self.rd_sector != self.rd_end_sector:
+                       count = min(self.rd_end_sector-self.rd_sector, (fis_max_dwords*4)//logical_sector_size)
+                       packet = self.read(self.rd_sector, count)
+                       packet.insert(0, 0)
+                       packets.append(FIS_DATA(packet, direction="D2H"))
+                       self.rd_sector += count
+               packets.append(FIS_REG_D2H())
+               return packets
+
+       def data_callback(self, fis):
+               self.write(self.wr_sector, fis.packet[1:])
+               self.wr_sector += dwords2sectors(len(fis.packet[1:]))
+               if self.wr_sector == self.wr_end_sector:
+                       return [FIS_REG_D2H()]
+               else:
+                       return [FIS_DMA_ACTIVATE_D2H()]
diff --git a/litesata/test/link_tb.py b/litesata/test/link_tb.py
new file mode 100644 (file)
index 0000000..daca230
--- /dev/null
@@ -0,0 +1,48 @@
+from litesata.common import *
+from litesata.core.link import LiteSATALink
+
+from litesata.test.common import *
+from litesata.test.hdd import *
+
+class LinkStreamer(PacketStreamer):
+       def __init__(self):
+               PacketStreamer.__init__(self, link_description(32), LinkTXPacket)
+
+class LinkLogger(PacketLogger):
+       def __init__(self):
+               PacketLogger.__init__(self, link_description(32), LinkRXPacket)
+
+class TB(Module):
+       def __init__(self):
+               self.hdd = HDD(
+                               link_debug=False, link_random_level=50,
+                               transport_debug=False, transport_loopback=True)
+               self.link = InsertReset(LiteSATALink(self.hdd.phy))
+
+               self.streamer = LinkStreamer()
+               self.streamer_randomizer = Randomizer(link_description(32), level=50)
+
+               self.logger_randomizer = Randomizer(link_description(32), level=50)
+               self.logger = LinkLogger()
+
+               self.pipeline = Pipeline(
+                       self.streamer,
+                       self.streamer_randomizer,
+                       self.link,
+                       self.logger_randomizer,
+                       self.logger
+               )
+
+       def gen_simulation(self, selfp):
+               for i in range(8):
+                       streamer_packet = LinkTXPacket([i for i in range(64)])
+                       yield from self.streamer.send(streamer_packet)
+                       yield from self.logger.receive()
+
+                       # 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=2048, vcd_name="my.vcd", keep_files=True)
diff --git a/litesata/test/phy_datapath_tb.py b/litesata/test/phy_datapath_tb.py
new file mode 100644 (file)
index 0000000..7107103
--- /dev/null
@@ -0,0 +1,88 @@
+from litesata.common import *
+from litesata.phy.datapath import liteSATAPHYDatapath
+
+from litesata.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.cd_sata_rx = ClockDomain()
+               self.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=10)
+               self.trx = TRX()
+               self.ctrl = CTRL()
+               self.datapath = LiteSATAPHYDatapath(self.trx, self.ctrl)
+               self.logger_randomizer = Randomizer(phy_description(32), level=10)
+               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)
diff --git a/litesata/test/scrambler.c b/litesata/test/scrambler.c
new file mode 100644 (file)
index 0000000..cee4b30
--- /dev/null
@@ -0,0 +1,113 @@
+// Adapted from SATA specification
+/****************************************************************************/
+/*                                                                          */
+/* scramble.c                                                               */
+/*                                                                          */
+/* This sample code generates the entire sequence of 65535 Dwords produced  */
+/* by the scrambler defined in the Serial ATA specification. The            */
+/* specification calls for an LFSR to generate a string of bits that will   */
+/* be packaged into 32 bit Dwords to be XORed with the data Dwords. The     */
+/* generator polynomial specified is:                                       */
+/*         16  15  13  4                                                    */
+/* G(x) = x + x + x + x + 1                                                 */
+/*                                                                          */
+/* Parallelized versions of the scrambler are initialized to a value        */
+/* derived from the initialization value of 0xFFFF defined in the           */
+/* specification. This implementation is initialized to 0xF0F6. Other       */
+/* parallel implementations will have different initial values. The         */
+/* important point is that the first Dword output of any implementation     */
+/* must equal 0xC2D2768D.                                                   */
+/* This code does not represent an elegant solution for a C implementation, */
+/* but it does demonstrate a method of generating the sequence that can be  */
+/* easily implemented in hardware. A block diagram of the circuit emulated  */
+/* by this code is shown below.                                             */
+/*                                                                          */
+/* +-----------------------------------+                                    */
+/* |                                   |                                    */
+/* |                                   |                                    */
+/* |     +---+                +---+    |                                    */
+/* |     | R |                | * |    |                                    */
+/* +---->| e |----------+---->| M |----+----> Output(31 downto 16)          */
+/*       | g |          |     | 1 |                                         */
+/*       +---+          |     +---+                                         */
+/*                      |                                                   */
+/*                      |     +---+                                         */
+/*                      |     | * |                                         */
+/*                      +---->| M |---------> Output(15 downto 0)           */
+/*                            | 2 |                                         */
+/*                            +---+                                         */
+/*                                                                          */
+/* The register shown in the block diagram is a 16 bit register. The two    */
+/* boxes, *M1 and *M2, each represent a multiply by a 16 by 16 binary       */
+/* matrix. A 16 by 16 matrix times a 16 bit vector yields a 16 bit vector.  */
+/* The two vectors are the two halves of the 32 bit scrambler value. The    */
+/* upper half of the scrambler value is stored back into the context        */
+/* register to be used to generate the next value in the scrambler          */
+/*                                                                          */
+/****************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+int main(int argc, char *argv[])
+{
+   int               i, j;
+   unsigned int      length;
+   unsigned short    context;
+   unsigned long     scrambler;
+   unsigned char     now[16];
+   unsigned char     next[32];
+   context = 0xF0F6;
+
+   scanf("0x%8x", &length);
+
+   for (i = 0; i < length; ++i)  {
+      for (j = 0; j < 16; ++j)  {
+         now[j] = (context >> j) & 0x01;
+      }
+      next[31] = now[12] ^ now[10] ^ now[7]  ^ now[3]  ^ now[1]  ^ now[0];
+      next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9]  ^ now[6]  ^ now[3]  ^ now[2]  ^ now[0];
+      next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8]  ^ now[5]  ^ now[3]  ^ now[2]  ^ now[1];
+      next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9]  ^ now[7]  ^ now[4]  ^ now[2]  ^ now[1]  ^ now[0];
+      next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9]  ^ now[8]  ^ now[6]  ^ now[1]  ^ now[0];
+      next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[5]  ^ now[3]  ^ now[0];
+      next[25] = now[15] ^ now[10] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[6]  ^ now[4]  ^ now[3]  ^ now[2];
+      next[24] = now[14] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[6]  ^ now[5]  ^ now[3]  ^ now[2]  ^ now[1];
+      next[23] = now[13] ^ now[8]  ^ now[7]  ^ now[6]  ^ now[5]  ^ now[4]  ^ now[2]  ^ now[1]  ^ now[0];
+      next[22] = now[15] ^ now[14] ^ now[7]  ^ now[6]  ^ now[5]  ^ now[4]  ^ now[1]  ^ now[0];
+      next[21] = now[15] ^ now[13] ^ now[12] ^ now[6]  ^ now[5]  ^ now[4]  ^ now[0];
+      next[20] = now[15] ^ now[11] ^ now[5]  ^ now[4];
+      next[19] = now[14] ^ now[10] ^ now[4]  ^ now[3];
+      next[18] = now[13] ^ now[9]  ^ now[3]  ^ now[2];
+      next[17] = now[12] ^ now[8]  ^ now[2]  ^ now[1];
+      next[16] = now[11] ^ now[7]  ^ now[1]  ^ now[0];
+
+
+      next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6]  ^ now[3]  ^ now[0];
+      next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9]  ^ now[5]  ^ now[3]  ^ now[2];
+      next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8]  ^ now[4]  ^ now[2]  ^ now[1];
+      next[12] = now[13] ^ now[11] ^ now[10] ^ now[9]  ^ now[7]  ^ now[3]  ^ now[1]  ^ now[0];
+      next[11] = now[15] ^ now[14] ^ now[10] ^ now[9]  ^ now[8]  ^ now[6]  ^ now[3]  ^ now[2]  ^ now[0];
+      next[10] = now[15] ^ now[13] ^ now[12] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[5]  ^ now[3]  ^ now[2]  ^ now[1];
+      next[9]  = now[14] ^ now[12] ^ now[11] ^ now[8]  ^ now[7]  ^ now[6]  ^ now[4]  ^ now[2]  ^ now[1]  ^ now[0];
+      next[8]  = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7]  ^ now[6]  ^ now[5]  ^ now[1]  ^ now[0];
+      next[7]  = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9]  ^ now[6]  ^ now[5]  ^ now[4]  ^ now[3]  ^ now[0];
+      next[6]  = now[15] ^ now[10] ^ now[9]  ^ now[8]  ^ now[5]  ^ now[4]  ^ now[2];
+      next[5]  = now[14] ^ now[9]  ^ now[8]  ^ now[7]  ^ now[4]  ^ now[3]  ^ now[1];
+      next[4]  = now[13] ^ now[8]  ^ now[7]  ^ now[6]  ^ now[3]  ^ now[2]  ^ now[0];
+      next[3]  = now[15] ^ now[14] ^ now[7]  ^ now[6]  ^ now[5]  ^ now[3]  ^ now[2]  ^ now[1];
+      next[2]  = now[14] ^ now[13] ^ now[6]  ^ now[5]  ^ now[4]  ^ now[2]  ^ now[1]  ^ now[0];
+      next[1]  = now[15] ^ now[14] ^ now[13] ^ now[5]  ^ now[4]  ^ now[1]  ^ now[0];
+      next[0]  = now[15] ^ now[13] ^ now[4]  ^ now[0];
+
+      scrambler = 0;
+      for (j = 31; j >= 0; --j)  {
+         scrambler = scrambler << 1;
+         scrambler |= next[j];
+      }
+      context = scrambler >> 16;
+      printf("%08x\n", (unsigned int) scrambler);
+
+   }
+
+   return 0;
+
+}
\ No newline at end of file
diff --git a/litesata/test/scrambler_tb.py b/litesata/test/scrambler_tb.py
new file mode 100644 (file)
index 0000000..bf29e50
--- /dev/null
@@ -0,0 +1,49 @@
+import subprocess
+
+from litesata.common import *
+from litesata.core.link.scrambler import *
+
+from litesata.test.common import *
+
+class TB(Module):
+       def __init__(self, length):
+               self.scrambler = InsertReset(Scrambler())
+               self.length = length
+
+       def get_c_values(self, length):
+               stdin = "0x%08x" %length
+               with subprocess.Popen("./scrambler", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+                       process.stdin.write(stdin.encode("ASCII"))
+                       out, err = process.communicate()
+               return [int(e, 16) for e in out.decode("ASCII").split("\n")[:-1]]
+
+       def gen_simulation(self, selfp):
+               # init CRC
+               selfp.scrambler.ce = 1
+               selfp.scrambler.reset = 1
+               yield
+               selfp.scrambler.reset = 0
+
+               # log results
+               yield
+               sim_values = []
+               for i in range(self.length):
+                       sim_values.append(selfp.scrambler.value)
+                       yield
+
+               # stop
+               selfp.scrambler.ce = 0
+               for i in range(32):
+                       yield
+
+               # get C code reference
+               c_values = self.get_c_values(self.length)
+
+               # check results
+               s, l, e = check(c_values, sim_values)
+               print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+if __name__ == "__main__":
+       from migen.sim.generic import run_simulation
+       length = 8192
+       run_simulation(TB(length), ncycles=length+100, vcd_name="my.vcd")
index 479f7347fb8ddc76ceca111c41eff4485d7f2fae..14cd891522dc8948b220061ef0d457eb00f6ffb2 100644 (file)
@@ -73,7 +73,7 @@ _io = [
                IOStandard("LVCMOS25")
        ),
 
-       ("sata_host", 0,
+       ("sata0", 0,
                Subsignal("refclk_p", Pins("C8")),
                Subsignal("refclk_n", Pins("C7")),
                Subsignal("txp", Pins("D2")),
@@ -81,15 +81,6 @@ _io = [
                Subsignal("rxp", Pins("E4")),
                Subsignal("rxn", Pins("E3")),
        ),
-
-       ("sata_device", 0,
-               Subsignal("refclk_p", Pins("G8")), # 125MHz SGMII
-               Subsignal("refclk_n", Pins("G7")), # 125MHz SGMII
-               Subsignal("txp", Pins("H2")), # SFP
-               Subsignal("txn", Pins("H1")), # SFP
-               Subsignal("rxp", Pins("G4")), # SFP
-               Subsignal("rxn", Pins("G3")), # SFP
-       ),
 ]
 
 def Platform(*args, toolchain="vivado", programmer="xc3sprog", **kwargs):
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..ec8de13
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+
+import sys, os
+from setuptools import setup
+from setuptools import find_packages
+
+here = os.path.abspath(os.path.dirname(__file__))
+README = open(os.path.join(here, "README")).read()
+
+required_version = (3, 3)
+if sys.version_info < required_version:
+       raise SystemExit("LiteSATA requires python {0} or greater".format(
+               ".".join(map(str, required_version))))
+
+setup(
+       name="litesata",
+       version="unknown",
+       description="Generic open-source SATA1/2/3 controller",
+       long_description=README,
+       author="Florent Kermarrec",
+       author_email="florent@enjoy-digital.fr",
+       url="http://enjoy-digital.fr",
+       download_url="https://github.com/Florent-Kermarrec/litesata",
+       packages=find_packages(here),
+       license="GPL",
+       platforms=["Any"],
+       keywords="HDL ASIC FPGA hardware design",
+       classifiers=[
+               "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
+               "Environment :: Console",
+               "Development Status :: Alpha",
+               "Intended Audience :: Developers",
+               "License :: OSI Approved :: GNU General Public License (GPL)",
+               "Operating System :: OS Independent",
+               "Programming Language :: Python",
+       ],
+)
diff --git a/targets/bist.py b/targets/bist.py
deleted file mode 100644 (file)
index d0ee9b6..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-import os
-
-from migen.fhdl.std import *
-from migen.bank import csrgen
-from migen.bus import wishbone, csr
-from migen.bus import wishbone2csr
-from migen.genlib.cdc import *
-from migen.genlib.resetsync import AsyncResetSynchronizer
-from migen.bank.description import *
-
-from miscope import MiLa, Term, UART2Wishbone
-
-from misoclib import identifier
-from lib.sata.common import *
-from lib.sata.phy import SATAPHY
-from lib.sata import SATACON
-from lib.sata.bist import SATABIST
-
-class _CRG(Module):
-       def __init__(self, platform):
-               self.cd_sys = ClockDomain()
-               self.sata_reset = Signal()
-
-               clk200 = platform.request("clk200")
-               clk200_se = Signal()
-               self.specials += Instance("IBUFDS", i_I=clk200.p, i_IB=clk200.n, o_O=clk200_se)
-
-               pll_locked = Signal()
-               pll_fb = Signal()
-               pll_sys = Signal()
-               self.specials += [
-                       Instance("PLLE2_BASE",
-                               p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
-
-                               # VCO @ 1GHz
-                               p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0,
-                               p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1,
-                               i_CLKIN1=clk200_se, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb,
-
-                               # 166MHz
-                               p_CLKOUT0_DIVIDE=6, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys,
-
-                               p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, #o_CLKOUT1=,
-
-                               p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=0.0, #o_CLKOUT2=,
-
-                               p_CLKOUT3_DIVIDE=2, p_CLKOUT3_PHASE=0.0, #o_CLKOUT3=,
-
-                               p_CLKOUT4_DIVIDE=2, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4=
-                       ),
-                       Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk),
-                       AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset") | self.sata_reset),
-               ]
-
-class GenSoC(Module):
-       csr_base = 0x00000000
-       csr_data_width = 32
-       csr_map = {
-               "uart2wb":                      0,
-               "identifier":           2,
-       }
-       interrupt_map = {}
-       cpu_type = None
-       def __init__(self, platform, clk_freq):
-               # UART <--> Wishbone bridge
-               self.uart2wb = UART2Wishbone(platform.request("serial"), clk_freq, baud=921600)
-
-               # CSR bridge   0x00000000 (shadow @0x00000000)
-               self.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(self.csr_data_width))
-               self._wb_masters = [self.uart2wb.wishbone]
-               self._wb_slaves = [(lambda a: a[23:25] == 0, self.wishbone2csr.wishbone)]
-               self.cpu_csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
-
-               # CSR
-               self.identifier = identifier.Identifier(0, int(clk_freq), 0)
-
-       def add_cpu_memory_region(self, name, origin, length):
-               self.cpu_memory_regions.append((name, origin, length))
-
-       def add_cpu_csr_region(self, name, origin, busword, obj):
-               self.cpu_csr_regions.append((name, origin, busword, obj))
-
-       def do_finalize(self):
-               # Wishbone
-               self.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
-                       self._wb_slaves, register=True)
-
-               # CSR
-               self.csrbankarray = csrgen.BankArray(self,
-                       lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
-                       data_width=self.csr_data_width)
-               self.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses())
-               for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
-                       self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), csrs)
-               for name, memory, mapaddr, mmap in self.csrbankarray.srams:
-                       self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), memory)
-
-class BISTLeds(Module):
-       def __init__(self, platform, sata_phy):
-               # 1Hz blinking leds (sata_rx and sata_tx clocks)
-               sata_rx_led = platform.request("user_led", 0)
-               sata_tx_led = platform.request("user_led", 1)
-
-               sata_rx_cnt = Signal(32)
-               sata_tx_cnt = Signal(32)
-
-               sata_freqs_mhz = {
-                       "SATA3" :       150.0,
-                       "SATA2" :       75.0,
-                       "SATA1" :       37.5,
-               }
-               sata_freq = int(sata_freqs_mhz[sata_phy.speed]*1000*1000)
-
-               self.sync.sata_rx += \
-                       If(sata_rx_cnt == 0,
-                               sata_rx_led.eq(~sata_rx_led),
-                               sata_rx_cnt.eq(sata_freq//2)
-                       ).Else(
-                               sata_rx_cnt.eq(sata_rx_cnt-1)
-                       )
-
-               self.sync.sata_tx += \
-                       If(sata_tx_cnt == 0,
-                               sata_tx_led.eq(~sata_tx_led),
-                               sata_tx_cnt.eq(sata_freq//2)
-                       ).Else(
-                               sata_tx_cnt.eq(sata_tx_cnt-1)
-                       )
-
-               # ready leds (crg and ctrl)
-               self.comb += platform.request("user_led", 2).eq(sata_phy.crg.ready)
-               self.comb += platform.request("user_led", 3).eq(sata_phy.ctrl.ready)
-
-class BISTSoC(GenSoC, AutoCSR):
-       default_platform = "kc705"
-       csr_map = {
-               "sata_bist":    10,
-       }
-       csr_map.update(GenSoC.csr_map)
-
-       def __init__(self, platform, export_mila=False):
-               clk_freq = 166*1000000
-               GenSoC.__init__(self, platform, clk_freq)
-               self.crg = _CRG(platform)
-
-               # SATA PHY and controller
-               self.sata_phy = SATAPHY(platform.request("sata_host"), clk_freq, speed="SATA2")
-               self.comb += self.crg.sata_reset.eq(self.sata_phy.ctrl.need_reset)
-               self.sata_con = SATACON(self.sata_phy)
-
-               # SATA BIST generator and checker
-               self.sata_bist = SATABIST(self.sata_con.crossbar.get_ports(3), with_control=True)
-
-               # Status Leds
-               self.leds = BISTLeds(platform, self.sata_phy)
-
-class BISTSoCDevel(BISTSoC, AutoCSR):
-       csr_map = {
-               "mila":                 11
-       }
-       csr_map.update(BISTSoC.csr_map)
-       def __init__(self, platform, export_mila=False):
-               BISTSoC.__init__(self, platform, export_mila)
-
-               self.sata_con_link_rx_fsm_state = Signal(4)
-               self.sata_con_link_tx_fsm_state = Signal(4)
-               self.sata_con_transport_rx_fsm_state = Signal(4)
-               self.sata_con_transport_tx_fsm_state = Signal(4)
-               self.sata_con_command_rx_fsm_state = Signal(4)
-               self.sata_con_command_tx_fsm_state = Signal(4)
-
-               debug = (
-                       self.sata_phy.ctrl.ready,
-
-                       self.sata_phy.source.stb,
-                       self.sata_phy.source.data,
-                       self.sata_phy.source.charisk,
-
-                       self.sata_phy.sink.stb,
-                       self.sata_phy.sink.data,
-                       self.sata_phy.sink.charisk,
-
-                       self.sata_con.command.sink.stb,
-                       self.sata_con.command.sink.sop,
-                       self.sata_con.command.sink.eop,
-                       self.sata_con.command.sink.ack,
-                       self.sata_con.command.sink.write,
-                       self.sata_con.command.sink.read,
-                       self.sata_con.command.sink.identify,
-
-                       self.sata_con.command.source.stb,
-                       self.sata_con.command.source.sop,
-                       self.sata_con.command.source.eop,
-                       self.sata_con.command.source.ack,
-                       self.sata_con.command.source.write,
-                       self.sata_con.command.source.read,
-                       self.sata_con.command.source.identify,
-                       self.sata_con.command.source.success,
-                       self.sata_con.command.source.failed,
-                       self.sata_con.command.source.data,
-
-                       self.sata_con_link_rx_fsm_state,
-                       self.sata_con_link_tx_fsm_state,
-                       self.sata_con_transport_rx_fsm_state,
-                       self.sata_con_transport_tx_fsm_state,
-                       self.sata_con_command_rx_fsm_state,
-                       self.sata_con_command_tx_fsm_state,
-               )
-
-               self.mila = MiLa(depth=2048, dat=Cat(*debug))
-               self.mila.add_port(Term)
-               if export_mila:
-                       mila_filename = os.path.join(platform.soc_ext_path, "test", "mila.csv")
-                       self.mila.export(self, debug, mila_filename)
-       def do_finalize(self):
-               BISTSoC.do_finalize(self)
-               self.comb += [
-                       self.sata_con_link_rx_fsm_state.eq(self.sata_con.link.rx.fsm.state),
-                       self.sata_con_link_tx_fsm_state.eq(self.sata_con.link.tx.fsm.state),
-                       self.sata_con_transport_rx_fsm_state.eq(self.sata_con.transport.rx.fsm.state),
-                       self.sata_con_transport_tx_fsm_state.eq(self.sata_con.transport.tx.fsm.state),
-                       self.sata_con_command_rx_fsm_state.eq(self.sata_con.command.rx.fsm.state),
-                       self.sata_con_command_tx_fsm_state.eq(self.sata_con.command.tx.fsm.state)
-               ]
-
-default_subtarget = BISTSoC
-#default_subtarget = BISTSoCDevel
diff --git a/targets/bist_kc705.py b/targets/bist_kc705.py
new file mode 100644 (file)
index 0000000..ff752d1
--- /dev/null
@@ -0,0 +1,225 @@
+import os
+
+from litesata.common import *
+from migen.bank import csrgen
+from migen.bus import wishbone, csr
+from migen.bus import wishbone2csr
+from migen.genlib.cdc import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+from migen.bank.description import *
+
+from misoclib import identifier
+
+from miscope import MiLa, Term, UART2Wishbone
+
+from litesata.common import *
+from litesata.phy import LiteSATAPHY
+from litesata import LiteSATA
+
+class _CRG(Module):
+       def __init__(self, platform):
+               self.cd_sys = ClockDomain()
+               self.reset = Signal()
+
+               clk200 = platform.request("clk200")
+               clk200_se = Signal()
+               self.specials += Instance("IBUFDS", i_I=clk200.p, i_IB=clk200.n, o_O=clk200_se)
+
+               pll_locked = Signal()
+               pll_fb = Signal()
+               pll_sys = Signal()
+               self.specials += [
+                       Instance("PLLE2_BASE",
+                               p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
+
+                               # VCO @ 1GHz
+                               p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0,
+                               p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1,
+                               i_CLKIN1=clk200_se, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb,
+
+                               # 166MHz
+                               p_CLKOUT0_DIVIDE=6, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys,
+
+                               p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, #o_CLKOUT1=,
+
+                               p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=0.0, #o_CLKOUT2=,
+
+                               p_CLKOUT3_DIVIDE=2, p_CLKOUT3_PHASE=0.0, #o_CLKOUT3=,
+
+                               p_CLKOUT4_DIVIDE=2, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4=
+                       ),
+                       Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk),
+                       AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset") | self.reset),
+               ]
+
+class GenSoC(Module):
+       csr_base = 0x00000000
+       csr_data_width = 32
+       csr_map = {
+               "uart2wb":                      0,
+               "identifier":           2,
+       }
+       interrupt_map = {}
+       cpu_type = None
+       def __init__(self, platform, clk_freq):
+               # UART <--> Wishbone bridge
+               self.uart2wb = UART2Wishbone(platform.request("serial"), clk_freq, baud=921600)
+
+               # CSR bridge   0x00000000 (shadow @0x00000000)
+               self.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(self.csr_data_width))
+               self._wb_masters = [self.uart2wb.wishbone]
+               self._wb_slaves = [(lambda a: a[23:25] == 0, self.wishbone2csr.wishbone)]
+               self.cpu_csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
+
+               # CSR
+               self.identifier = identifier.Identifier(0, int(clk_freq), 0)
+
+       def add_cpu_memory_region(self, name, origin, length):
+               self.cpu_memory_regions.append((name, origin, length))
+
+       def add_cpu_csr_region(self, name, origin, busword, obj):
+               self.cpu_csr_regions.append((name, origin, busword, obj))
+
+       def do_finalize(self):
+               # Wishbone
+               self.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
+                       self._wb_slaves, register=True)
+
+               # CSR
+               self.csrbankarray = csrgen.BankArray(self,
+                       lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
+                       data_width=self.csr_data_width)
+               self.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses())
+               for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
+                       self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), csrs)
+               for name, memory, mapaddr, mmap in self.csrbankarray.srams:
+                       self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), memory)
+
+class BISTLeds(Module):
+       def __init__(self, platform, sata_phy):
+               # 1Hz blinking leds (sata_rx and sata_tx clocks)
+               sata_rx_led = platform.request("user_led", 0)
+               sata_tx_led = platform.request("user_led", 1)
+
+               sata_rx_cnt = Signal(32)
+               sata_tx_cnt = Signal(32)
+
+               sata_freqs_mhz = {
+                       "SATA3" :       150.0,
+                       "SATA2" :       75.0,
+                       "SATA1" :       37.5,
+               }
+               sata_freq = int(sata_freqs_mhz[sata_phy.speed]*1000*1000)
+
+               self.sync.sata_rx += \
+                       If(sata_rx_cnt == 0,
+                               sata_rx_led.eq(~sata_rx_led),
+                               sata_rx_cnt.eq(sata_freq//2)
+                       ).Else(
+                               sata_rx_cnt.eq(sata_rx_cnt-1)
+                       )
+
+               self.sync.sata_tx += \
+                       If(sata_tx_cnt == 0,
+                               sata_tx_led.eq(~sata_tx_led),
+                               sata_tx_cnt.eq(sata_freq//2)
+                       ).Else(
+                               sata_tx_cnt.eq(sata_tx_cnt-1)
+                       )
+
+               # ready leds (crg and ctrl)
+               self.comb += platform.request("user_led", 2).eq(sata_phy.crg.ready)
+               self.comb += platform.request("user_led", 3).eq(sata_phy.ctrl.ready)
+
+class BISTSoC(GenSoC, AutoCSR):
+       default_platform = "kc705"
+       csr_map = {
+               "sata":         10,
+       }
+       csr_map.update(GenSoC.csr_map)
+
+       def __init__(self, platform, export_mila=False):
+               clk_freq = 166*1000000
+               GenSoC.__init__(self, platform, clk_freq)
+               self.crg = _CRG(platform)
+
+               # SATA PHY/Core/Frontend
+               self.sata_phy = LiteSATAPHY(platform.device, platform.request("sata0"), "SATA2", clk_freq)
+               self.comb += self.crg.reset.eq(self.sata_phy.ctrl.need_reset) # XXX FIXME
+               self.sata = LiteSATA(self.sata_phy, with_crossbar=True, with_bist=True, with_bist_csr=True)
+
+               # Status Leds
+               self.leds = BISTLeds(platform, self.sata_phy)
+
+class BISTSoCDevel(BISTSoC, AutoCSR):
+       csr_map = {
+               "mila":                 11
+       }
+       csr_map.update(BISTSoC.csr_map)
+       def __init__(self, platform, export_mila=False):
+               BISTSoC.__init__(self, platform, export_mila)
+
+               self.sata_core_link_rx_fsm_state = Signal(4)
+               self.sata_core_link_tx_fsm_state = Signal(4)
+               self.sata_core_transport_rx_fsm_state = Signal(4)
+               self.sata_core_transport_tx_fsm_state = Signal(4)
+               self.sata_core_command_rx_fsm_state = Signal(4)
+               self.sata_core_command_tx_fsm_state = Signal(4)
+
+               debug = (
+                       self.sata_phy.ctrl.ready,
+
+                       self.sata_phy.source.stb,
+                       self.sata_phy.source.data,
+                       self.sata_phy.source.charisk,
+
+                       self.sata_phy.sink.stb,
+                       self.sata_phy.sink.data,
+                       self.sata_phy.sink.charisk,
+
+                       self.sata.core.command.sink.stb,
+                       self.sata.core.command.sink.sop,
+                       self.sata.core.command.sink.eop,
+                       self.sata.core.command.sink.ack,
+                       self.sata.core.command.sink.write,
+                       self.sata.core.command.sink.read,
+                       self.sata.core.command.sink.identify,
+
+                       self.sata.core.command.source.stb,
+                       self.sata.core.command.source.sop,
+                       self.sata.core.command.source.eop,
+                       self.sata.core.command.source.ack,
+                       self.sata.core.command.source.write,
+                       self.sata.core.command.source.read,
+                       self.sata.core.command.source.identify,
+                       self.sata.core.command.source.success,
+                       self.sata.core.command.source.failed,
+                       self.sata.core.command.source.data,
+
+                       self.sata_core_link_rx_fsm_state,
+                       self.sata_core_link_tx_fsm_state,
+                       self.sata_core_transport_rx_fsm_state,
+                       self.sata_core_transport_tx_fsm_state,
+                       self.sata_core_command_rx_fsm_state,
+                       self.sata_core_command_tx_fsm_state,
+               )
+
+               self.mila = MiLa(depth=2048, dat=Cat(*debug))
+               self.mila.add_port(Term)
+               if export_mila:
+                       mila_filename = os.path.join(platform.soc_ext_path, "test", "mila.csv")
+                       self.mila.export(self, debug, mila_filename)
+
+       def do_finalize(self):
+               BISTSoC.do_finalize(self)
+               self.comb += [
+                       self.sata_core_link_rx_fsm_state.eq(self.sata.core.link.rx.fsm.state),
+                       self.sata_core_link_tx_fsm_state.eq(self.sata.core.link.tx.fsm.state),
+                       self.sata_core_transport_rx_fsm_state.eq(self.sata.core.transport.rx.fsm.state),
+                       self.sata_core_transport_tx_fsm_state.eq(self.sata.core.transport.tx.fsm.state),
+                       self.sata_core_command_rx_fsm_state.eq(self.sata.core.command.rx.fsm.state),
+                       self.sata_core_command_tx_fsm_state.eq(self.sata.core.command.tx.fsm.state)
+               ]
+
+#default_subtarget = BISTSoC
+default_subtarget = BISTSoCDevel
index c0c577fa346a56c1bccfb78a92a84b562b35c64c..69272ffe0c27b63f0fee349363495f4a788ce3ec 100644 (file)
@@ -4,7 +4,7 @@ from config import *
 
 logical_sector_size = 512
 
-class SATABISTUnitDriver:
+class LiteSATABISTUnitDriver:
        def __init__(self, regs, name):
                self.regs = regs
                self.name = name
@@ -25,15 +25,15 @@ class SATABISTUnitDriver:
                errors = self.errors.read()
                return (speed, errors)
 
-class SATABISTGeneratorDriver(SATABISTUnitDriver):
+class LiteSATABISTGeneratorDriver(LiteSATABISTUnitDriver):
        def __init__(self, regs, name):
-               SATABISTUnitDriver.__init__(self, regs, name + "_generator")
+               LiteSATABISTUnitDriver.__init__(self, regs, name + "_generator")
 
-class SATABISTCheckerDriver(SATABISTUnitDriver):
+class LiteSATABISTCheckerDriver(LiteSATABISTUnitDriver):
        def __init__(self, regs, name):
-               SATABISTUnitDriver.__init__(self, regs, name + "_checker")
+               LiteSATABISTUnitDriver.__init__(self, regs, name + "_checker")
 
-class SATABISTIdentifyDriver:
+class LiteSATABISTIdentifyDriver:
        def __init__(self, regs, name):
                self.regs = regs
                self.name = name
@@ -58,13 +58,16 @@ class SATABISTIdentifyDriver:
        def decode(self):
                self.serial_number = ""
                for i, dword in enumerate(self.data[10:20]):
-                       s = dword.to_bytes(4, byteorder='big').decode("utf-8")
-                       self.serial_number += s[2:] + s[:2]
-
-       def __repr__(self):
-               r = "Serial Number: " + self.serial_number
+                       try:
+                               s = dword.to_bytes(4, byteorder='big').decode("utf-8")
+                               self.serial_number += s[2:] + s[:2]
+                       except:
+                               self.serial_number += "    "
+
+       def hdd_info(self):
+               info = "Serial Number: " + self.serial_number
                # XXX: enhance decode function
-               return r
+               print(info)
 
 KB = 1024
 MB = 1024*KB
@@ -88,12 +91,12 @@ if __name__ == "__main__":
        args = _get_args()
        wb.open()
        ###
-       identify = SATABISTIdentifyDriver(wb.regs, "sata_bist")
-       generator = SATABISTGeneratorDriver(wb.regs, "sata_bist")
-       checker = SATABISTCheckerDriver(wb.regs, "sata_bist")
+       identify = LiteSATABISTIdentifyDriver(wb.regs, "sata_bist")
+       generator = LiteSATABISTGeneratorDriver(wb.regs, "sata_bist")
+       checker = LiteSATABISTCheckerDriver(wb.regs, "sata_bist")
 
        identify.run()
-       print(identify)
+       identify.hdd_info()
 
        sector = 0
        count = int(args.transfer_size)*MB//logical_sector_size
index 3849dc0af72b78a7b35185c1c6b63be6eb34b28f..46e414113464ea97a0157da45edfbb60ea444122 100644 (file)
@@ -5,9 +5,9 @@ from bist import *
 from miscope.host.drivers import MiLaDriver
 
 mila = MiLaDriver(wb.regs, "mila")
-identify = SATABISTIdentifyDriver(wb.regs, "sata_bist")
-generator = SATABISTGeneratorDriver(wb.regs, "sata_bist")
-checker = SATABISTCheckerDriver(wb.regs, "sata_bist")
+identify = LiteSATABISTIdentifyDriver(wb.regs, "sata_bist")
+generator = LiteSATABISTGeneratorDriver(wb.regs, "sata_bist")
+checker = LiteSATABISTCheckerDriver(wb.regs, "sata_bist")
 wb.open()
 regs = wb.regs
 ###
@@ -18,27 +18,27 @@ if len(sys.argv) < 2:
 
 conditions = {}
 conditions["wr_cmd"] = {
-       "bistsocdevel_sata_con_command_sink_stb"                        : 1,
-       "bistsocdevel_sata_con_command_sink_payload_write"      : 1,
+       "bistsocdevel_core_sink_stb"                    : 1,
+       "bistsocdevel_core_sink_payload_write"  : 1,
 }
 conditions["wr_dma_activate"] = {
-       "bistsocdevel_sata_con_command_source_source_stb"                       : 1,
-       "bistsocdevel_sata_con_command_source_source_payload_write"     : 1,
+       "bistsocdevel_core_source_source_stb"                   : 1,
+       "bistsocdevel_core_source_source_payload_write" : 1,
 }
 conditions["rd_cmd"] = {
-       "bistsocdevel_sata_con_command_sink_stb"                        : 1,
-       "bistsocdevel_sata_con_command_sink_payload_read"       : 1,
+       "bistsocdevel_core_sink_stb"                    : 1,
+       "bistsocdevel_core_sink_payload_read"   : 1,
 }
 conditions["rd_data"] = {
-       "bistsocdevel_sata_con_command_source_source_stb"                       : 1,
-       "bistsocdevel_sata_con_command_source_source_payload_read"      : 1,
+       "bistsocdevel_core_source_source_stb"                   : 1,
+       "bistsocdevel_core_source_source_payload_read"  : 1,
 }
 conditions["id_cmd"] = {
-       "bistsocdevel_sata_con_command_sink_stb"                                : 1,
-       "bistsocdevel_sata_con_command_sink_payload_identify"   : 1,
+       "bistsocdevel_core_sink_stb"                            : 1,
+       "bistsocdevel_core_sink_payload_identify"       : 1,
 }
 conditions["id_pio_setup"] = {
-       "bistsocdevel_sata_phy_source_source_payload_data" : primitives["X_RDY"],
+       "bistsocdevel_source_source_payload_data" : primitives["X_RDY"],
 }
 
 mila.prog_term(port=0, cond=conditions[sys.argv[1]])
@@ -58,6 +58,6 @@ mila.export("dump.vcd")
 wb.close()
 
 print_link_trace(mila,
-       tx_data_name="bistsocdevel_sata_phy_sink_sink_payload_data",
-       rx_data_name="bistsocdevel_sata_phy_source_source_payload_data"
+       tx_data_name="bistsocdevel_sink_sink_payload_data",
+       rx_data_name="bistsocdevel_source_source_payload_data"
 )