diff --git a/lib/sata/link/crc.py b/lib/sata/link/crc.py
index 8f4830056..59c650a17 100644
--- a/lib/sata/link/crc.py
+++ b/lib/sata/link/crc.py
@@ -54,12 +54,12 @@ class CRCEngine(Module):
# compute and optimize CRC's LFSR
curval = [[("new", i)] for i in range(width)]
for i in range(width):
- feedback = curval.pop()
- curval.insert(0, feedback)
- for j in range(1, width-1):
- if (polynom&(1< scrambler_ref
+ $(CMD) scrambler_tb.py
clean:
rm crc crc_ref scrambler scrambler_ref
diff --git a/lib/sata/link/test/scrambler.c b/lib/sata/link/test/scrambler.c
index f1711f157..cc96459b4 100644
--- a/lib/sata/link/test/scrambler.c
+++ b/lib/sata/link/test/scrambler.c
@@ -1,4 +1,50 @@
// 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
#include
int main(int argc, char *argv[])
diff --git a/lib/sata/link/test/scrambler_tb.py b/lib/sata/link/test/scrambler_tb.py
new file mode 100644
index 000000000..301b12516
--- /dev/null
+++ b/lib/sata/link/test/scrambler_tb.py
@@ -0,0 +1,54 @@
+from subprocess import check_output
+
+from migen.fhdl.std import *
+
+from lib.sata.std import *
+from lib.sata.link.scrambler import *
+
+def check(ref, res):
+ 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
+
+class TB(Module):
+ def __init__(self):
+ self.submodules.scrambler = SATAScrambler()
+
+ def gen_simulation(self, selfp):
+
+ # init CRC
+ selfp.scrambler.ce = 1
+ selfp.scrambler.reset = 1
+ yield
+ selfp.scrambler.reset = 0
+
+ # get C code results
+ ref = []
+ f = open("scrambler_ref", "r")
+ for l in f:
+ ref.append(int(l, 16))
+ f.close()
+
+ # log results
+ yield
+ res = []
+ for i in range(256):
+ res.append(selfp.scrambler.value)
+ yield
+ for e in res:
+ print("%08x" %e)
+
+ # check results
+ s, l, e = check(ref, res)
+ print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+if __name__ == "__main__":
+ from migen.sim.generic import run_simulation
+ run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True)