link: add CRC and testbench
This commit is contained in:
parent
449daedab7
commit
8062298668
|
@ -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)
|
||||||
|
]
|
|
@ -1,4 +1,4 @@
|
||||||
MSCDIR = ../../../
|
MSCDIR = ../../../../
|
||||||
PYTHON = python3
|
PYTHON = python3
|
||||||
|
|
||||||
CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
|
CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
|
||||||
|
@ -9,6 +9,7 @@ CFLAGS =-Wall -O0
|
||||||
crc_tb:
|
crc_tb:
|
||||||
$(CC) $(CFLAGS) $(INC) -o crc crc.c
|
$(CC) $(CFLAGS) $(INC) -o crc crc.c
|
||||||
./crc /> crc_ref
|
./crc /> crc_ref
|
||||||
|
$(CMD) crc_tb.py
|
||||||
|
|
||||||
scrambler_tb:
|
scrambler_tb:
|
||||||
$(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
|
$(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
|
||||||
|
|
|
@ -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)
|
|
@ -0,0 +1,8 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
|
||||||
|
def phy_layout(dw):
|
||||||
|
layout = [
|
||||||
|
("p_packetized", True),
|
||||||
|
("d", dw)
|
||||||
|
]
|
||||||
|
return layout
|
Loading…
Reference in New Issue