link: improve and clean up crc_tb, scrambler_tb
This commit is contained in:
parent
2b7779d3b6
commit
31b9132dd9
|
@ -90,7 +90,7 @@ class SATACRC(Module):
|
|||
polynom = 0x04C11DB7
|
||||
init = 0x52325032
|
||||
check = 0xC704DD7B
|
||||
def __init__(self, dat_width):
|
||||
def __init__(self):
|
||||
self.d = Signal(self.width)
|
||||
self.value = Signal(self.width)
|
||||
self.error = Signal()
|
||||
|
|
|
@ -20,4 +20,4 @@ link_tb:
|
|||
all: crc_tb scrambler_tb
|
||||
|
||||
clean:
|
||||
rm crc scrambler
|
||||
rm crc scrambler *.vcd
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
def seed_to_data(seed, random=True):
|
||||
if random:
|
||||
return (seed * 0x31415979 + 1) & 0xffffffff
|
||||
else:
|
||||
return seed
|
||||
|
||||
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
|
||||
if isinstance(ref, int):
|
||||
return 0, 1, int(ref != res)
|
||||
else:
|
||||
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
|
||||
|
|
|
@ -1,4 +1,35 @@
|
|||
// Adapted from SATA specification
|
||||
/****************************************************************************/
|
||||
/* */
|
||||
/* crc.c */
|
||||
/* */
|
||||
/* This sample code reads standard in for a sequence of 32 bit values */
|
||||
/* formatted in hexadecimal with a leading "0x" (e.g. 0xDEADBEEF). The */
|
||||
/* code calculates the Serial ATA CRC for the input data stream. The */
|
||||
/* generator polynomial used is: */
|
||||
/* 32 26 23 22 16 12 11 10 8 7 5 4 2 */
|
||||
/* G(x) = x + x + x + x + x + x + x + x + x + x + x + x + x + x + 1 */
|
||||
/* */
|
||||
/* This sample code uses a parallel implementation of the CRC calculation */
|
||||
/* circuit that is suitable for implementation in hardware. A block */
|
||||
/* diagram of the circuit being emulated is shown below. */
|
||||
/* */
|
||||
/* +---+ +---+ +---+ */
|
||||
/* Data_In --------->| | | | | R | */
|
||||
/* | + |--------->| * |--------->| e |----+ */
|
||||
/* +---->| | | | | g | | */
|
||||
/* | +---+ +---+ +---+ | */
|
||||
/* | | */
|
||||
/* | | */
|
||||
/* +--------------------------------------------+ */
|
||||
/* */
|
||||
/* The CRC value is initialized to 0x52325032 as defined in the Serial ATA */
|
||||
/* specification. */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -10,19 +41,23 @@ int main(int argc, char *argv[])
|
|||
unsigned char crc_bit[32];
|
||||
unsigned char new_bit[32];
|
||||
|
||||
data_in = 0x12345678;
|
||||
crc = 0x52325032;
|
||||
data_count = 0;
|
||||
|
||||
while (data_count < 65536) {
|
||||
while((scanf(" 0x%8x", &data_in) == 1) && (!scanf("exit"))) {
|
||||
data_count++;
|
||||
|
||||
/* Add the data_in value to the current value of the CRC held in the */
|
||||
/* "register". The addition is performed modulo two (XOR). */
|
||||
crc ^= data_in;
|
||||
|
||||
/* Expand the value of the CRC held in the register to 32 individual */
|
||||
/* bits for easy manipulation. */
|
||||
for (i = 0; i < 32; ++i) {
|
||||
crc_bit[i] = (crc >> i) & 0x01;
|
||||
}
|
||||
|
||||
/* The following 32 assignments perform the function of the box */
|
||||
/* labeled "*" in the block diagram above. The new_bit array is a */
|
||||
/* temporary holding place for the new CRC value being calculated. */
|
||||
/* Note that there are lots of shared terms in the assignments below. */
|
||||
new_bit[31] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^
|
||||
crc_bit[23] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[5];
|
||||
new_bit[30] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^
|
||||
|
@ -100,13 +135,15 @@ int main(int argc, char *argv[])
|
|||
new_bit[0] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^
|
||||
crc_bit[16] ^ crc_bit[12] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[0];
|
||||
|
||||
/* The new CRC value has been calculated as individual bits in the */
|
||||
/* new_bit array. Re-assembled it into a 32 bit value and "clock" it */
|
||||
/* into the "register". */
|
||||
crc = 0;
|
||||
for (i = 31; i >= 0; --i) {
|
||||
crc = crc << 1;
|
||||
crc |= new_bit[i];
|
||||
}
|
||||
printf("%08x\n", crc);
|
||||
}
|
||||
|
||||
printf("%08x\n", crc);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -4,38 +4,57 @@ from migen.fhdl.std import *
|
|||
|
||||
from lib.sata.std import *
|
||||
from lib.sata.link.crc import *
|
||||
from lib.sata.link.test.common import check
|
||||
from lib.sata.link.test.common import *
|
||||
|
||||
class TB(Module):
|
||||
def __init__(self, length):
|
||||
def __init__(self, length, random):
|
||||
self.submodules.crc = SATACRC()
|
||||
self.length = length
|
||||
self.random = random
|
||||
|
||||
def get_c_crc(self, datas):
|
||||
stdin = ""
|
||||
for data in datas:
|
||||
stdin += "0x%08x " %data
|
||||
stdin += "exit"
|
||||
with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
|
||||
process.stdin.write(stdin.encode("UTF-8"))
|
||||
out, err = process.communicate()
|
||||
return int(out.decode("UTF-8"), 16)
|
||||
|
||||
def gen_simulation(self, selfp):
|
||||
# init CRC
|
||||
selfp.crc.d = 0x12345678
|
||||
# init CRC
|
||||
selfp.crc.d = 0
|
||||
selfp.crc.ce = 1
|
||||
selfp.crc.reset = 1
|
||||
yield
|
||||
selfp.crc.reset = 0
|
||||
|
||||
# get C code results
|
||||
p = subprocess.Popen(["./crc"], stdout=subprocess.PIPE)
|
||||
out, err = p.communicate()
|
||||
ref = [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]]
|
||||
|
||||
|
||||
# log results
|
||||
res = []
|
||||
# feed CRC with datas
|
||||
datas = []
|
||||
for i in range(self.length):
|
||||
res.append(selfp.crc.value)
|
||||
data = seed_to_data(i, self.random)
|
||||
datas.append(data)
|
||||
selfp.crc.d = data
|
||||
yield
|
||||
|
||||
# check results
|
||||
s, l, e = check(ref, res)
|
||||
# log results
|
||||
yield
|
||||
sim_crc = selfp.crc.value
|
||||
|
||||
# stop
|
||||
selfp.crc.ce = 0
|
||||
for i in range(32):
|
||||
yield
|
||||
|
||||
# get C core reference
|
||||
c_crc = self.get_c_crc(datas)
|
||||
|
||||
# check results
|
||||
s, l, e = check(c_crc, sim_crc)
|
||||
print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
|
||||
|
||||
if __name__ == "__main__":
|
||||
from migen.sim.generic import run_simulation
|
||||
length = 8192
|
||||
run_simulation(TB(length), ncycles=length+100, vcd_name="my.vcd", keep_files=True)
|
||||
run_simulation(TB(length, True), ncycles=length+100, vcd_name="my.vcd")
|
||||
|
|
|
@ -50,13 +50,16 @@
|
|||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
unsigned int length;
|
||||
unsigned short context;
|
||||
unsigned long scrambler;
|
||||
unsigned char now[16];
|
||||
unsigned char next[32];
|
||||
context = 0xF0F6;
|
||||
|
||||
for (i = 0; i < 65536; ++i) {
|
||||
scanf("0x%8x", &length);
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
for (j = 0; j < 16; ++j) {
|
||||
now[j] = (context >> j) & 0x01;
|
||||
}
|
||||
|
|
|
@ -4,37 +4,47 @@ from migen.fhdl.std import *
|
|||
|
||||
from lib.sata.std import *
|
||||
from lib.sata.link.scrambler import *
|
||||
from lib.sata.link.test.common import check
|
||||
from lib.sata.link.test.common import *
|
||||
|
||||
class TB(Module):
|
||||
def __init__(self, length):
|
||||
self.submodules.scrambler = Scrambler()
|
||||
self.length = length
|
||||
|
||||
def get_c_values(self, length):
|
||||
stdin = "0x%08x" %length
|
||||
with subprocess.Popen("./scrambler", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
|
||||
process.stdin.write(stdin.encode("UTF-8"))
|
||||
out, err = process.communicate()
|
||||
return [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]]
|
||||
|
||||
def gen_simulation(self, selfp):
|
||||
# init CRC
|
||||
# init CRC
|
||||
selfp.scrambler.ce = 1
|
||||
selfp.scrambler.reset = 1
|
||||
yield
|
||||
selfp.scrambler.reset = 0
|
||||
|
||||
# get C code results
|
||||
p = subprocess.Popen(["./scrambler"], stdout=subprocess.PIPE)
|
||||
out, err = p.communicate()
|
||||
ref = [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]]
|
||||
|
||||
# log results
|
||||
# log results
|
||||
yield
|
||||
res = []
|
||||
sim_values = []
|
||||
for i in range(self.length):
|
||||
res.append(selfp.scrambler.value)
|
||||
sim_values.append(selfp.scrambler.value)
|
||||
yield
|
||||
|
||||
# check results
|
||||
s, l, e = check(ref, res)
|
||||
# stop
|
||||
selfp.scrambler.ce = 0
|
||||
for i in range(32):
|
||||
yield
|
||||
|
||||
# get C code reference
|
||||
c_values = self.get_c_values(self.length)
|
||||
|
||||
# check results
|
||||
s, l, e = check(c_values, sim_values)
|
||||
print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
|
||||
|
||||
if __name__ == "__main__":
|
||||
from migen.sim.generic import run_simulation
|
||||
length = 8192
|
||||
run_simulation(TB(length), ncycles=length+100, vcd_name="my.vcd", keep_files=True)
|
||||
run_simulation(TB(length), ncycles=length+100, vcd_name="my.vcd")
|
||||
|
|
|
@ -22,21 +22,15 @@ def ones(width):
|
|||
return 2**width-1
|
||||
|
||||
def phy_layout(dw):
|
||||
parameters = {
|
||||
"packetized": False
|
||||
}
|
||||
layout = [
|
||||
("data", dw),
|
||||
("charisk", dw//8),
|
||||
]
|
||||
return EndpointDescription(layout, parameters)
|
||||
return EndpointDescription(layout, packetized=False)
|
||||
|
||||
def link_layout(dw):
|
||||
parameters = {
|
||||
"packetized": True
|
||||
}
|
||||
layout = [
|
||||
("d", dw),
|
||||
("error", 1)
|
||||
]
|
||||
return EndpointDescription(layout, parameters)
|
||||
return EndpointDescription(layout, packetized=True)
|
||||
|
|
Loading…
Reference in New Issue