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)