From 31b9132dd9c79ee3d34480fb5ef81317e63e1e95 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 2 Dec 2014 19:24:46 +0100 Subject: [PATCH] link: improve and clean up crc_tb, scrambler_tb --- lib/sata/link/crc.py | 2 +- lib/sata/link/test/Makefile | 2 +- lib/sata/link/test/common.py | 29 +++++++++++------ lib/sata/link/test/crc.c | 51 ++++++++++++++++++++++++++---- lib/sata/link/test/crc_tb.py | 51 ++++++++++++++++++++---------- lib/sata/link/test/scrambler.c | 5 ++- lib/sata/link/test/scrambler_tb.py | 36 +++++++++++++-------- lib/sata/std.py | 10 ++---- 8 files changed, 129 insertions(+), 57 deletions(-) diff --git a/lib/sata/link/crc.py b/lib/sata/link/crc.py index 2f3aa367a..e7bb3bb0e 100644 --- a/lib/sata/link/crc.py +++ b/lib/sata/link/crc.py @@ -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() diff --git a/lib/sata/link/test/Makefile b/lib/sata/link/test/Makefile index 4f621c37b..e516221c2 100644 --- a/lib/sata/link/test/Makefile +++ b/lib/sata/link/test/Makefile @@ -20,4 +20,4 @@ link_tb: all: crc_tb scrambler_tb clean: - rm crc scrambler + rm crc scrambler *.vcd diff --git a/lib/sata/link/test/common.py b/lib/sata/link/test/common.py index d95c8352a..c5994f020 100644 --- a/lib/sata/link/test/common.py +++ b/lib/sata/link/test/common.py @@ -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 diff --git a/lib/sata/link/test/crc.c b/lib/sata/link/test/crc.c index f4f15954d..75576b5c1 100644 --- a/lib/sata/link/test/crc.c +++ b/lib/sata/link/test/crc.c @@ -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 #include 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; } diff --git a/lib/sata/link/test/crc_tb.py b/lib/sata/link/test/crc_tb.py index 6639a1939..0411fd04e 100644 --- a/lib/sata/link/test/crc_tb.py +++ b/lib/sata/link/test/crc_tb.py @@ -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") diff --git a/lib/sata/link/test/scrambler.c b/lib/sata/link/test/scrambler.c index d8b0d8303..cee4b30a9 100644 --- a/lib/sata/link/test/scrambler.c +++ b/lib/sata/link/test/scrambler.c @@ -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; } diff --git a/lib/sata/link/test/scrambler_tb.py b/lib/sata/link/test/scrambler_tb.py index 8228ef563..86a569ba2 100644 --- a/lib/sata/link/test/scrambler_tb.py +++ b/lib/sata/link/test/scrambler_tb.py @@ -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") diff --git a/lib/sata/std.py b/lib/sata/std.py index 191778fc1..e0f100ea7 100644 --- a/lib/sata/std.py +++ b/lib/sata/std.py @@ -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)