--- /dev/null
+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)
+ ]
--- /dev/null
+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)