move test
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 5 Dec 2014 16:48:01 +0000 (17:48 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 5 Dec 2014 16:48:01 +0000 (17:48 +0100)
16 files changed:
lib/sata/link/test/Makefile [deleted file]
lib/sata/link/test/bfm.py [deleted file]
lib/sata/link/test/common.py [deleted file]
lib/sata/link/test/crc.c [deleted file]
lib/sata/link/test/crc_tb.py [deleted file]
lib/sata/link/test/link_tb.py [deleted file]
lib/sata/link/test/scrambler.c [deleted file]
lib/sata/link/test/scrambler_tb.py [deleted file]
lib/sata/test/Makefile [new file with mode: 0644]
lib/sata/test/bfm.py [new file with mode: 0644]
lib/sata/test/common.py [new file with mode: 0644]
lib/sata/test/crc.c [new file with mode: 0644]
lib/sata/test/crc_tb.py [new file with mode: 0644]
lib/sata/test/link_tb.py [new file with mode: 0644]
lib/sata/test/scrambler.c [new file with mode: 0644]
lib/sata/test/scrambler_tb.py [new file with mode: 0644]

diff --git a/lib/sata/link/test/Makefile b/lib/sata/link/test/Makefile
deleted file mode 100644 (file)
index e516221..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-MSCDIR = ../../../../
-PYTHON = python3
-
-CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
-
-CC=gcc
-CFLAGS =-Wall -O0
-
-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
-
-link_tb:
-       $(CMD) link_tb.py
-
-all: crc_tb scrambler_tb
-
-clean:
-       rm crc scrambler *.vcd
diff --git a/lib/sata/link/test/bfm.py b/lib/sata/link/test/bfm.py
deleted file mode 100644 (file)
index f679146..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-import subprocess
-
-from migen.fhdl.std import *
-
-from lib.sata.std import *
-from lib.sata.link.test.common import *
-from lib.sata.transport.std import *
-
-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_layout(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_layout(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, debug):
-               self.debug = debug
-
-               self.submodules.rx = PHYSink()
-               self.submodules.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()
-               if self.debug:
-                               print(self)
-
-       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
-
-class LinkPacket(list):
-       def __init__(self):
-               self.ongoing = False
-               self.scrambled_datas = self.import_scrambler_datas()
-
-       def import_scrambler_datas(self):
-               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 LinkRXPacket(LinkPacket):
-       def decode(self):
-               self.descramble()
-               return self.check_crc()
-
-       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
-
-class LinkTXPacket(LinkPacket):
-       def encode(self):
-               self.scramble()
-               self.insert_crc()
-
-       def scramble(self):
-               for i in range(len(self)):
-                       self[i] = self[i] ^ self.scrambled_datas[i]
-
-       def insert_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)
-               self.append(crc)
-
-class LinkLayer(Module):
-       def  __init__(self, phy, debug, hold_random_level=0):
-               self.phy = phy
-               self.debug = debug
-               self.hold_random_level = hold_random_level
-               self.tx_packet = LinkTXPacket()
-               self.rx_packet = LinkRXPacket()
-               self.rx_cont = False
-
-               self.transport_callback = None
-
-       def set_transport_callback(self, callback):
-               self.transport_callback = callback
-
-       def callback(self, dword):
-               if dword == primitives["CONT"]:
-                       self.rx_cont = True
-               elif is_primitive(dword):
-                       self.rx_cont = False
-
-               if dword == primitives["X_RDY"]:
-                       self.phy.send(primitives["R_RDY"])
-
-               elif dword == primitives["WTRM"]:
-                       self.phy.send(primitives["R_OK"])
-
-               elif dword == primitives["HOLD"]:
-                       self.phy.send(primitives["HOLDA"])
-
-               elif dword == primitives["EOF"]:
-                       self.rx_packet.decode()
-                       if self.transport_callback is not None:
-                               self.transport_callback(self.rx_packet)
-                       self.rx_packet.ongoing = False
-
-               elif self.rx_packet.ongoing:
-                       if dword != primitives["HOLD"]:
-                               n = randn(100)
-                               if n < self.hold_random_level:
-                                       self.phy.send(primitives["HOLD"])
-                               else:
-                                       self.phy.send(primitives["R_RDY"])
-                               if not is_primitive(dword):
-                                       if not self.rx_cont:
-                                               self.rx_packet.append(dword)
-
-               elif dword == primitives["SOF"]:
-                       self.rx_packet = LinkRXPacket()
-                       self.rx_packet.ongoing = True
-
-       def send(self, packet):
-               pass
-
-       def gen_simulation(self, selfp):
-               self.phy.send(primitives["SYNC"])
-               while True:
-                       yield from self.phy.receive()
-                       self.callback(self.phy.rx.dword.dat)
-
-def get_field_data(field, packet):
-       return (packet[field.dword] >> field.offset) & (2**field.width-1)
-
-class FIS:
-       def __init__(self, packet, layout):
-               self.packet = packet
-               self.layout = layout
-               self.decode()
-
-       def decode(self):
-               for k, v in self.layout.items():
-                       setattr(self, k, get_field_data(v, self.packet))
-
-       def encode(self):
-               for k, v in self.layout.items():
-                       self.packet[v.dword] |= (getattr(self, k) << v.offset)
-
-       def __repr__(self):
-               r = "--------\n"
-               for k in sorted(self.layout.keys()):
-                       r += k + " : 0x%x" %getattr(self,k) + "\n"
-               return r
-
-class FIS_REG_H2D(FIS):
-       def __init__(self, packet=[0]*fis_reg_h2d_len):
-               FIS.__init__(self, packet,fis_reg_h2d_layout)
-
-       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_len):
-               FIS.__init__(self, packet,fis_reg_d2h_layout)
-
-       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_len):
-               FIS.__init__(self, packet,fis_dma_activate_d2h_layout)
-
-       def __repr__(self):
-               r = "FIS_DMA_ACTIVATE_D2H\n"
-               r += FIS.__repr__(self)
-               return r
-
-class FIS_DMA_SETUP(FIS):
-       def __init__(self, packet=[0]*fis_dma_setup_len):
-               FIS.__init__(self, packet,fis_dma_setup_layout)
-
-       def __repr__(self):
-               r = "FIS_DMA_SETUP\n"
-               r += FIS.__repr__(self)
-               return r
-
-class FIS_DATA(FIS):
-       def __init__(self, packet=[0]):
-               FIS.__init__(self, packet,fis_data_layout)
-
-       def __repr__(self):
-               r = "FIS_DATA\n"
-               r += FIS.__repr__(self)
-               return r
-
-class FIS_PIO_SETUP_D2H(FIS):
-       def __init__(self, packet=[0]*fis_pio_setup_d2h_len):
-               FIS.__init__(self, packet,fis_pio_setup_d2h_layout)
-
-       def __repr__(self):
-               r = "FIS_PIO_SETUP\n"
-               r += FIS.__repr__(self)
-               return r
-
-class FIS_UNKNOWN(FIS):
-       def __init__(self, packet=[0]):
-               FIS.__init__(self, packet, {})
-
-       def __repr__(self):
-               r = "UNKNOWN\n"
-               r += "--------\n"
-               for dword in self.packet:
-                       r += "%08x\n" %dword
-               return r
-
-class TransportLayer(Module):
-       def __init__(self, link):
-               pass
-
-       def callback(self, packet):
-               fis_type = packet[0]
-               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["DMA_SETUP"]:
-                       fis = FIS_SETUP(packet)
-               elif fis_type == fis_types["DATA"]:
-                       fis = FIS_DATA(packet)
-               elif fis_type == fis_types["PIO_SETUP_D2H"]:
-                       fis = FIS_PIO_SETUP_D2H(packet)
-               else:
-                       fis = FIS_UNKNOWN(packet)
-               print(fis)
-
-class BFM(Module):
-       def __init__(self, dw, debug=False, hold_random_level=0):
-               ###
-               self.submodules.phy = PHYLayer(debug)
-               self.submodules.link = LinkLayer(self.phy, debug, hold_random_level)
-               self.submodules.transport = TransportLayer(self.link)
-               self.link.set_transport_callback(self.transport.callback)
diff --git a/lib/sata/link/test/common.py b/lib/sata/link/test/common.py
deleted file mode 100644 (file)
index 80986b4..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-import random
-
-from lib.sata.std import *
-
-def seed_to_data(seed, random=True):
-       if random:
-               return (seed * 0x31415979 + 1) & 0xffffffff
-       else:
-               return seed
-
-def check(ref, res):
-       if isinstance(ref, int):
-               return 0, 1, int(ref != res)
-       else:
-               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 AckRandomizer(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/link/test/crc.c b/lib/sata/link/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/link/test/crc_tb.py b/lib/sata/link/test/crc_tb.py
deleted file mode 100644 (file)
index a4bd51b..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-import subprocess
-
-from migen.fhdl.std import *
-
-from lib.sata.std import *
-from lib.sata.link.crc import *
-from lib.sata.link.test.common import *
-
-class TB(Module):
-       def __init__(self, length, random):
-               self.submodules.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/link/test/link_tb.py b/lib/sata/link/test/link_tb.py
deleted file mode 100644 (file)
index 5a7d4aa..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-import random
-
-from migen.fhdl.std import *
-from migen.genlib.record import *
-from migen.sim.generic import run_simulation
-
-from lib.sata.std import *
-from lib.sata.link import SATALinkLayer
-
-from lib.sata.link.test.bfm import *
-from lib.sata.link.test.common import *
-
-class LinkPacket():
-       def __init__(self, d=[]):
-               self.d = d
-               self.start = 1
-               self.done = 0
-
-class LinkStreamer(Module):
-       def __init__(self, dw):
-               self.source = Source(link_layout(dw))
-               ###
-               self.packets = []
-               self.packet = LinkPacket()
-               self.packet.done = 1
-
-       def send(self, packet, blocking=True):
-               self.packets.append(packet)
-               if blocking:
-                       while packet.done == 0:
-                               yield
-
-       def do_simulation(self, selfp):
-               if len(self.packets) and self.packet.done:
-                       self.packet = self.packets.pop(0)
-               if self.packet.start and not self.packet.done:
-                       selfp.source.stb = 1
-                       selfp.source.sop = 1
-                       selfp.source.d = self.packet.d.pop(0)
-                       self.packet.start = 0
-               elif selfp.source.stb == 1 and selfp.source.ack == 1:
-                       selfp.source.sop = 0
-                       selfp.source.eop = (len(self.packet.d) == 1)
-                       if len(self.packet.d) > 0:
-                               selfp.source.stb = 1
-                               selfp.source.d = self.packet.d.pop(0)
-                       else:
-                               self.packet.done = 1
-                               selfp.source.stb = 0
-
-class LinkLogger(Module):
-       def __init__(self, dw):
-               self.sink = Sink(link_layout(dw))
-               ###
-               self.packet = LinkPacket()
-
-       def receive(self):
-               self.packet.done = 0
-               while self.packet.done == 0:
-                       yield
-
-       def do_simulation(self, selfp):
-               self.packet.done = 0
-               selfp.sink.ack = 1
-               if selfp.sink.stb == 1 and selfp.sink.sop == 1:
-                       self.packet.start = 1
-                       self.packet.d = [selfp.sink.d]
-               elif selfp.sink.stb:
-                       self.packet.start = 0
-                       self.packet.d.append(selfp.sink.d)
-               if (selfp.sink.stb ==1 and selfp.sink.eop ==1):
-                       self.packet.done = 1
-
-class TB(Module):
-       def __init__(self):
-               self.submodules.bfm = BFM(32, debug=True, hold_random_level=50)
-               self.submodules.link_layer = SATALinkLayer(self.bfm.phy)
-
-               self.submodules.streamer = LinkStreamer(32)
-               streamer_ack_randomizer = AckRandomizer(link_layout(32), level=50)
-               self.submodules += streamer_ack_randomizer
-               self.submodules.logger = LinkLogger(32)
-               self.comb += [
-                       Record.connect(self.streamer.source, streamer_ack_randomizer.sink),
-                       Record.connect(streamer_ack_randomizer.source, self.link_layer.sink),
-                       Record.connect(self.link_layer.source, self.logger.sink)
-               ]
-
-       def gen_simulation(self, selfp):
-               for i in range(200):
-                       yield
-               for i in range(8):
-                       yield from self.streamer.send(LinkPacket([i for i in range(16)]))
-
-if __name__ == "__main__":
-       run_simulation(TB(), ncycles=512, vcd_name="my.vcd", keep_files=True)
diff --git a/lib/sata/link/test/scrambler.c b/lib/sata/link/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/link/test/scrambler_tb.py b/lib/sata/link/test/scrambler_tb.py
deleted file mode 100644 (file)
index 9f2ad8d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-import subprocess
-
-from migen.fhdl.std import *
-
-from lib.sata.std import *
-from lib.sata.link.scrambler import *
-from lib.sata.link.test.common import *
-
-class TB(Module):
-       def __init__(self, length):
-               self.submodules.scrambler = 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/test/Makefile b/lib/sata/test/Makefile
new file mode 100644 (file)
index 0000000..abb4d60
--- /dev/null
@@ -0,0 +1,23 @@
+MSCDIR = ../../../
+PYTHON = python3
+
+CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
+
+CC=gcc
+CFLAGS =-Wall -O0
+
+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
+
+link_tb:
+       $(CMD) link_tb.py
+
+all: crc_tb scrambler_tb
+
+clean:
+       rm crc scrambler *.vcd
diff --git a/lib/sata/test/bfm.py b/lib/sata/test/bfm.py
new file mode 100644 (file)
index 0000000..af7a268
--- /dev/null
@@ -0,0 +1,309 @@
+import subprocess
+
+from migen.fhdl.std import *
+
+from lib.sata.std import *
+from lib.sata.transport.std import *
+
+from lib.sata.test.common import *
+
+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_layout(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_layout(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, debug):
+               self.debug = debug
+
+               self.submodules.rx = PHYSink()
+               self.submodules.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()
+               if self.debug:
+                               print(self)
+
+       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
+
+class LinkPacket(list):
+       def __init__(self):
+               self.ongoing = False
+               self.scrambled_datas = self.import_scrambler_datas()
+
+       def import_scrambler_datas(self):
+               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 LinkRXPacket(LinkPacket):
+       def decode(self):
+               self.descramble()
+               return self.check_crc()
+
+       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
+
+class LinkTXPacket(LinkPacket):
+       def encode(self):
+               self.scramble()
+               self.insert_crc()
+
+       def scramble(self):
+               for i in range(len(self)):
+                       self[i] = self[i] ^ self.scrambled_datas[i]
+
+       def insert_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)
+               self.append(crc)
+
+class LinkLayer(Module):
+       def  __init__(self, phy, debug, hold_random_level=0):
+               self.phy = phy
+               self.debug = debug
+               self.hold_random_level = hold_random_level
+               self.tx_packet = LinkTXPacket()
+               self.rx_packet = LinkRXPacket()
+               self.rx_cont = False
+
+               self.transport_callback = None
+
+       def set_transport_callback(self, callback):
+               self.transport_callback = callback
+
+       def callback(self, dword):
+               if dword == primitives["CONT"]:
+                       self.rx_cont = True
+               elif is_primitive(dword):
+                       self.rx_cont = False
+
+               if dword == primitives["X_RDY"]:
+                       self.phy.send(primitives["R_RDY"])
+
+               elif dword == primitives["WTRM"]:
+                       self.phy.send(primitives["R_OK"])
+
+               elif dword == primitives["HOLD"]:
+                       self.phy.send(primitives["HOLDA"])
+
+               elif dword == primitives["EOF"]:
+                       self.rx_packet.decode()
+                       if self.transport_callback is not None:
+                               self.transport_callback(self.rx_packet)
+                       self.rx_packet.ongoing = False
+
+               elif self.rx_packet.ongoing:
+                       if dword != primitives["HOLD"]:
+                               n = randn(100)
+                               if n < self.hold_random_level:
+                                       self.phy.send(primitives["HOLD"])
+                               else:
+                                       self.phy.send(primitives["R_RDY"])
+                               if not is_primitive(dword):
+                                       if not self.rx_cont:
+                                               self.rx_packet.append(dword)
+
+               elif dword == primitives["SOF"]:
+                       self.rx_packet = LinkRXPacket()
+                       self.rx_packet.ongoing = True
+
+       def send(self, packet):
+               pass
+
+       def gen_simulation(self, selfp):
+               self.phy.send(primitives["SYNC"])
+               while True:
+                       yield from self.phy.receive()
+                       self.callback(self.phy.rx.dword.dat)
+
+def get_field_data(field, packet):
+       return (packet[field.dword] >> field.offset) & (2**field.width-1)
+
+class FIS:
+       def __init__(self, packet, layout):
+               self.packet = packet
+               self.layout = layout
+               self.decode()
+
+       def decode(self):
+               for k, v in self.layout.items():
+                       setattr(self, k, get_field_data(v, self.packet))
+
+       def encode(self):
+               for k, v in self.layout.items():
+                       self.packet[v.dword] |= (getattr(self, k) << v.offset)
+
+       def __repr__(self):
+               r = "--------\n"
+               for k in sorted(self.layout.keys()):
+                       r += k + " : 0x%x" %getattr(self,k) + "\n"
+               return r
+
+class FIS_REG_H2D(FIS):
+       def __init__(self, packet=[0]*fis_reg_h2d_len):
+               FIS.__init__(self, packet,fis_reg_h2d_layout)
+
+       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_len):
+               FIS.__init__(self, packet,fis_reg_d2h_layout)
+
+       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_len):
+               FIS.__init__(self, packet,fis_dma_activate_d2h_layout)
+
+       def __repr__(self):
+               r = "FIS_DMA_ACTIVATE_D2H\n"
+               r += FIS.__repr__(self)
+               return r
+
+class FIS_DMA_SETUP(FIS):
+       def __init__(self, packet=[0]*fis_dma_setup_len):
+               FIS.__init__(self, packet,fis_dma_setup_layout)
+
+       def __repr__(self):
+               r = "FIS_DMA_SETUP\n"
+               r += FIS.__repr__(self)
+               return r
+
+class FIS_DATA(FIS):
+       def __init__(self, packet=[0]):
+               FIS.__init__(self, packet,fis_data_layout)
+
+       def __repr__(self):
+               r = "FIS_DATA\n"
+               r += FIS.__repr__(self)
+               return r
+
+class FIS_PIO_SETUP_D2H(FIS):
+       def __init__(self, packet=[0]*fis_pio_setup_d2h_len):
+               FIS.__init__(self, packet,fis_pio_setup_d2h_layout)
+
+       def __repr__(self):
+               r = "FIS_PIO_SETUP\n"
+               r += FIS.__repr__(self)
+               return r
+
+class FIS_UNKNOWN(FIS):
+       def __init__(self, packet=[0]):
+               FIS.__init__(self, packet, {})
+
+       def __repr__(self):
+               r = "UNKNOWN\n"
+               r += "--------\n"
+               for dword in self.packet:
+                       r += "%08x\n" %dword
+               return r
+
+class TransportLayer(Module):
+       def __init__(self, link):
+               pass
+
+       def callback(self, packet):
+               fis_type = packet[0]
+               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["DMA_SETUP"]:
+                       fis = FIS_SETUP(packet)
+               elif fis_type == fis_types["DATA"]:
+                       fis = FIS_DATA(packet)
+               elif fis_type == fis_types["PIO_SETUP_D2H"]:
+                       fis = FIS_PIO_SETUP_D2H(packet)
+               else:
+                       fis = FIS_UNKNOWN(packet)
+               print(fis)
+
+class BFM(Module):
+       def __init__(self, dw, debug=False, hold_random_level=0):
+               ###
+               self.submodules.phy = PHYLayer(debug)
+               self.submodules.link = LinkLayer(self.phy, debug, hold_random_level)
+               self.submodules.transport = TransportLayer(self.link)
+               self.link.set_transport_callback(self.transport.callback)
diff --git a/lib/sata/test/common.py b/lib/sata/test/common.py
new file mode 100644 (file)
index 0000000..80986b4
--- /dev/null
@@ -0,0 +1,51 @@
+import random
+
+from lib.sata.std import *
+
+def seed_to_data(seed, random=True):
+       if random:
+               return (seed * 0x31415979 + 1) & 0xffffffff
+       else:
+               return seed
+
+def check(ref, res):
+       if isinstance(ref, int):
+               return 0, 1, int(ref != res)
+       else:
+               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 AckRandomizer(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/crc.c b/lib/sata/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/lib/sata/test/crc_tb.py b/lib/sata/test/crc_tb.py
new file mode 100644 (file)
index 0000000..0ce17dc
--- /dev/null
@@ -0,0 +1,61 @@
+import subprocess
+
+from migen.fhdl.std import *
+
+from lib.sata.std import *
+from lib.sata.link.crc import *
+
+from lib.sata.test.common import *
+
+class TB(Module):
+       def __init__(self, length, random):
+               self.submodules.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/link_tb.py b/lib/sata/test/link_tb.py
new file mode 100644 (file)
index 0000000..3260034
--- /dev/null
@@ -0,0 +1,96 @@
+import random
+
+from migen.fhdl.std import *
+from migen.genlib.record import *
+from migen.sim.generic import run_simulation
+
+from lib.sata.std import *
+from lib.sata.link import SATALinkLayer
+
+from lib.sata.test.bfm import *
+from lib.sata.test.common import *
+
+class LinkPacket():
+       def __init__(self, d=[]):
+               self.d = d
+               self.start = 1
+               self.done = 0
+
+class LinkStreamer(Module):
+       def __init__(self, dw):
+               self.source = Source(link_layout(dw))
+               ###
+               self.packets = []
+               self.packet = LinkPacket()
+               self.packet.done = 1
+
+       def send(self, packet, blocking=True):
+               self.packets.append(packet)
+               if blocking:
+                       while packet.done == 0:
+                               yield
+
+       def do_simulation(self, selfp):
+               if len(self.packets) and self.packet.done:
+                       self.packet = self.packets.pop(0)
+               if self.packet.start and not self.packet.done:
+                       selfp.source.stb = 1
+                       selfp.source.sop = 1
+                       selfp.source.d = self.packet.d.pop(0)
+                       self.packet.start = 0
+               elif selfp.source.stb == 1 and selfp.source.ack == 1:
+                       selfp.source.sop = 0
+                       selfp.source.eop = (len(self.packet.d) == 1)
+                       if len(self.packet.d) > 0:
+                               selfp.source.stb = 1
+                               selfp.source.d = self.packet.d.pop(0)
+                       else:
+                               self.packet.done = 1
+                               selfp.source.stb = 0
+
+class LinkLogger(Module):
+       def __init__(self, dw):
+               self.sink = Sink(link_layout(dw))
+               ###
+               self.packet = LinkPacket()
+
+       def receive(self):
+               self.packet.done = 0
+               while self.packet.done == 0:
+                       yield
+
+       def do_simulation(self, selfp):
+               self.packet.done = 0
+               selfp.sink.ack = 1
+               if selfp.sink.stb == 1 and selfp.sink.sop == 1:
+                       self.packet.start = 1
+                       self.packet.d = [selfp.sink.d]
+               elif selfp.sink.stb:
+                       self.packet.start = 0
+                       self.packet.d.append(selfp.sink.d)
+               if (selfp.sink.stb ==1 and selfp.sink.eop ==1):
+                       self.packet.done = 1
+
+class TB(Module):
+       def __init__(self):
+               self.submodules.bfm = BFM(32, debug=True, hold_random_level=50)
+               self.submodules.link_layer = SATALinkLayer(self.bfm.phy)
+
+               self.submodules.streamer = LinkStreamer(32)
+               streamer_ack_randomizer = AckRandomizer(link_layout(32), level=50)
+               self.submodules += streamer_ack_randomizer
+               self.submodules.logger = LinkLogger(32)
+               self.comb += [
+                       Record.connect(self.streamer.source, streamer_ack_randomizer.sink),
+                       Record.connect(streamer_ack_randomizer.source, self.link_layer.sink),
+                       Record.connect(self.link_layer.source, self.logger.sink)
+               ]
+
+       def gen_simulation(self, selfp):
+               for i in range(200):
+                       yield
+               for i in range(8):
+                       yield from self.streamer.send(LinkPacket([i for i in range(16)]))
+
+if __name__ == "__main__":
+       run_simulation(TB(), ncycles=512, vcd_name="my.vcd", keep_files=True)
diff --git a/lib/sata/test/scrambler.c b/lib/sata/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/lib/sata/test/scrambler_tb.py b/lib/sata/test/scrambler_tb.py
new file mode 100644 (file)
index 0000000..3100dc9
--- /dev/null
@@ -0,0 +1,51 @@
+import subprocess
+
+from migen.fhdl.std import *
+
+from lib.sata.std import *
+from lib.sata.link.scrambler import *
+
+from lib.sata.test.common import *
+
+class TB(Module):
+       def __init__(self, length):
+               self.submodules.scrambler = 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")