link: add CRC and testbench

This commit is contained in:
Florent Kermarrec 2014-11-03 18:54:41 +01:00
parent 449daedab7
commit 8062298668
4 changed files with 168 additions and 1 deletions

106
lib/sata/link/crc.py Normal file
View File

@ -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)
]

View 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

View File

@ -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)

8
lib/sata/std.py Normal file
View File

@ -0,0 +1,8 @@
from migen.fhdl.std import *
def phy_layout(dw):
layout = [
("p_packetized", True),
("d", dw)
]
return layout