link: add CRC and testbench
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 3 Nov 2014 17:54:41 +0000 (18:54 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 4 Nov 2014 09:33:11 +0000 (10:33 +0100)
lib/sata/link/crc.py [new file with mode: 0644]
lib/sata/link/test/Makefile
lib/sata/link/test/crc_tb.py [new file with mode: 0644]
lib/sata/std.py [new file with mode: 0644]

diff --git a/lib/sata/link/crc.py b/lib/sata/link/crc.py
new file mode 100644 (file)
index 0000000..8f48300
--- /dev/null
@@ -0,0 +1,106 @@
+from migen.fhdl.std import *
+from migen.genlib.misc import optree
+
+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()
+                       curval.insert(0, feedback)
+                       for j in range(1, width-1):
+                               if (polynom&(1<<j)):
+                                       curval[j] += feedback
+                               curval[j] = _optimize_eq(curval[j])
+
+               # 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 = 0xC704DD7B
+       def __init__(self):
+               self.d = Signal(self.width)
+               self.value = Signal(self.width)
+               self.error = Signal()
+
+               ###
+
+               self.submodules.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)
+               ]
index e75c5fa3ccd39ab14b25db0a3d1e5674f8341296..92c9db9cf9ac2899173275059b4b2c3591f6e38d 100644 (file)
@@ -1,4 +1,4 @@
-MSCDIR = ../../../
+MSCDIR = ../../../../
 PYTHON = python3
 
 CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
@@ -9,6 +9,7 @@ CFLAGS =-Wall -O0
 crc_tb:
        $(CC) $(CFLAGS) $(INC) -o crc crc.c
        ./crc /> crc_ref
+       $(CMD) crc_tb.py
 
 scrambler_tb:
        $(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
diff --git a/lib/sata/link/test/crc_tb.py b/lib/sata/link/test/crc_tb.py
new file mode 100644 (file)
index 0000000..459e4e1
--- /dev/null
@@ -0,0 +1,52 @@
+from subprocess import check_output
+
+from migen.fhdl.std import *
+
+from lib.sata.std import *
+from lib.sata.link.crc 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.crc = SATACRC()
+
+       def gen_simulation(self, selfp):
+               
+       # init CRC
+               selfp.crc.d = 0x12345678
+               selfp.crc.ce = 1
+               selfp.crc.reset = 1
+               yield
+               selfp.crc.reset = 0
+
+       # get C code results
+               ref = []
+               f = open("crc_ref", "r")
+               for l in f:
+                       ref.append(int(l, 16))
+               f.close()
+
+       # log results
+               res = []
+               for i in range(256):
+                       res.append(selfp.crc.value)
+                       yield
+
+       # 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)
diff --git a/lib/sata/std.py b/lib/sata/std.py
new file mode 100644 (file)
index 0000000..3f3ea2f
--- /dev/null
@@ -0,0 +1,8 @@
+from migen.fhdl.std import *
+
+def phy_layout(dw):
+       layout = [
+               ("p_packetized", True),
+               ("d", dw)
+       ]
+       return layout