link: improve and clean up crc_tb, scrambler_tb

This commit is contained in:
Florent Kermarrec 2014-12-02 19:24:46 +01:00
parent 2b7779d3b6
commit 31b9132dd9
8 changed files with 129 additions and 57 deletions

View File

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

View File

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

View File

@ -1,4 +1,13 @@
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):
if isinstance(ref, int):
return 0, 1, int(ref != res)
else:
shift = 0 shift = 0
while((ref[0] != res[0]) and (len(res)>1)): while((ref[0] != res[0]) and (len(res)>1)):
res.pop(0) res.pop(0)

View File

@ -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;
} }

View File

@ -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
# 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 # check results
s, l, e = check(ref, res) 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")

View File

@ -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;
} }

View File

@ -4,13 +4,20 @@ 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
@ -18,23 +25,26 @@ class TB(Module):
yield yield
selfp.scrambler.reset = 0 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 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
# 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 # check results
s, l, e = check(ref, res) 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")

View File

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