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
|
polynom = 0x04C11DB7
|
||||||
init = 0x52325032
|
init = 0x52325032
|
||||||
check = 0xC704DD7B
|
check = 0xC704DD7B
|
||||||
def __init__(self, dat_width):
|
def __init__(self):
|
||||||
self.d = Signal(self.width)
|
self.d = Signal(self.width)
|
||||||
self.value = Signal(self.width)
|
self.value = Signal(self.width)
|
||||||
self.error = Signal()
|
self.error = Signal()
|
||||||
|
|
|
@ -20,4 +20,4 @@ link_tb:
|
||||||
all: crc_tb scrambler_tb
|
all: crc_tb scrambler_tb
|
||||||
|
|
||||||
clean:
|
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):
|
def check(ref, res):
|
||||||
shift = 0
|
if isinstance(ref, int):
|
||||||
while((ref[0] != res[0]) and (len(res)>1)):
|
return 0, 1, int(ref != res)
|
||||||
res.pop(0)
|
else:
|
||||||
shift += 1
|
shift = 0
|
||||||
length = min(len(ref), len(res))
|
while((ref[0] != res[0]) and (len(res)>1)):
|
||||||
errors = 0
|
res.pop(0)
|
||||||
for i in range(length):
|
shift += 1
|
||||||
if ref.pop(0) != res.pop(0):
|
length = min(len(ref), len(res))
|
||||||
errors += 1
|
errors = 0
|
||||||
return shift, length, errors
|
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
|
// 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 <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -10,19 +41,23 @@ int main(int argc, char *argv[])
|
||||||
unsigned char crc_bit[32];
|
unsigned char crc_bit[32];
|
||||||
unsigned char new_bit[32];
|
unsigned char new_bit[32];
|
||||||
|
|
||||||
data_in = 0x12345678;
|
|
||||||
crc = 0x52325032;
|
crc = 0x52325032;
|
||||||
data_count = 0;
|
data_count = 0;
|
||||||
|
|
||||||
while (data_count < 65536) {
|
while((scanf(" 0x%8x", &data_in) == 1) && (!scanf("exit"))) {
|
||||||
data_count++;
|
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;
|
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) {
|
for (i = 0; i < 32; ++i) {
|
||||||
crc_bit[i] = (crc >> i) & 0x01;
|
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] ^
|
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];
|
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] ^
|
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] ^
|
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];
|
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;
|
crc = 0;
|
||||||
for (i = 31; i >= 0; --i) {
|
for (i = 31; i >= 0; --i) {
|
||||||
crc = crc << 1;
|
crc = crc << 1;
|
||||||
crc |= new_bit[i];
|
crc |= new_bit[i];
|
||||||
}
|
}
|
||||||
printf("%08x\n", crc);
|
|
||||||
}
|
}
|
||||||
|
printf("%08x\n", crc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,38 +4,57 @@ from migen.fhdl.std import *
|
||||||
|
|
||||||
from lib.sata.std import *
|
from lib.sata.std import *
|
||||||
from lib.sata.link.crc 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):
|
class TB(Module):
|
||||||
def __init__(self, length):
|
def __init__(self, length, random):
|
||||||
self.submodules.crc = SATACRC()
|
self.submodules.crc = SATACRC()
|
||||||
self.length = length
|
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):
|
def gen_simulation(self, selfp):
|
||||||
# init CRC
|
# init CRC
|
||||||
selfp.crc.d = 0x12345678
|
selfp.crc.d = 0
|
||||||
selfp.crc.ce = 1
|
selfp.crc.ce = 1
|
||||||
selfp.crc.reset = 1
|
selfp.crc.reset = 1
|
||||||
yield
|
yield
|
||||||
selfp.crc.reset = 0
|
selfp.crc.reset = 0
|
||||||
|
|
||||||
# get C code results
|
# feed CRC with datas
|
||||||
p = subprocess.Popen(["./crc"], stdout=subprocess.PIPE)
|
datas = []
|
||||||
out, err = p.communicate()
|
|
||||||
ref = [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]]
|
|
||||||
|
|
||||||
|
|
||||||
# log results
|
|
||||||
res = []
|
|
||||||
for i in range(self.length):
|
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
|
yield
|
||||||
|
|
||||||
# check results
|
# log results
|
||||||
s, l, e = check(ref, res)
|
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))
|
print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from migen.sim.generic import run_simulation
|
from migen.sim.generic import run_simulation
|
||||||
length = 8192
|
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 main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
unsigned int length;
|
||||||
unsigned short context;
|
unsigned short context;
|
||||||
unsigned long scrambler;
|
unsigned long scrambler;
|
||||||
unsigned char now[16];
|
unsigned char now[16];
|
||||||
unsigned char next[32];
|
unsigned char next[32];
|
||||||
context = 0xF0F6;
|
context = 0xF0F6;
|
||||||
|
|
||||||
for (i = 0; i < 65536; ++i) {
|
scanf("0x%8x", &length);
|
||||||
|
|
||||||
|
for (i = 0; i < length; ++i) {
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
now[j] = (context >> j) & 0x01;
|
now[j] = (context >> j) & 0x01;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,37 +4,47 @@ from migen.fhdl.std import *
|
||||||
|
|
||||||
from lib.sata.std import *
|
from lib.sata.std import *
|
||||||
from lib.sata.link.scrambler 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):
|
class TB(Module):
|
||||||
def __init__(self, length):
|
def __init__(self, length):
|
||||||
self.submodules.scrambler = Scrambler()
|
self.submodules.scrambler = Scrambler()
|
||||||
self.length = length
|
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):
|
def gen_simulation(self, selfp):
|
||||||
# init CRC
|
# init CRC
|
||||||
selfp.scrambler.ce = 1
|
selfp.scrambler.ce = 1
|
||||||
selfp.scrambler.reset = 1
|
selfp.scrambler.reset = 1
|
||||||
yield
|
yield
|
||||||
selfp.scrambler.reset = 0
|
selfp.scrambler.reset = 0
|
||||||
|
|
||||||
# get C code results
|
# log 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
|
|
||||||
yield
|
yield
|
||||||
res = []
|
sim_values = []
|
||||||
for i in range(self.length):
|
for i in range(self.length):
|
||||||
res.append(selfp.scrambler.value)
|
sim_values.append(selfp.scrambler.value)
|
||||||
yield
|
yield
|
||||||
|
|
||||||
# check results
|
# stop
|
||||||
s, l, e = check(ref, res)
|
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))
|
print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from migen.sim.generic import run_simulation
|
from migen.sim.generic import run_simulation
|
||||||
length = 8192
|
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
|
return 2**width-1
|
||||||
|
|
||||||
def phy_layout(dw):
|
def phy_layout(dw):
|
||||||
parameters = {
|
|
||||||
"packetized": False
|
|
||||||
}
|
|
||||||
layout = [
|
layout = [
|
||||||
("data", dw),
|
("data", dw),
|
||||||
("charisk", dw//8),
|
("charisk", dw//8),
|
||||||
]
|
]
|
||||||
return EndpointDescription(layout, parameters)
|
return EndpointDescription(layout, packetized=False)
|
||||||
|
|
||||||
def link_layout(dw):
|
def link_layout(dw):
|
||||||
parameters = {
|
|
||||||
"packetized": True
|
|
||||||
}
|
|
||||||
layout = [
|
layout = [
|
||||||
("d", dw),
|
("d", dw),
|
||||||
("error", 1)
|
("error", 1)
|
||||||
]
|
]
|
||||||
return EndpointDescription(layout, parameters)
|
return EndpointDescription(layout, packetized=True)
|
||||||
|
|
Loading…
Reference in New Issue