From: Florent Kermarrec Date: Fri, 5 Dec 2014 16:48:01 +0000 (+0100) Subject: move test X-Git-Tag: 24jan2021_ls180~2572^2~150 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e900b9031c8a678dea987dfdf45894641dc5c021;p=litex.git move test --- diff --git a/lib/sata/link/test/Makefile b/lib/sata/link/test/Makefile deleted file mode 100644 index e516221c..00000000 --- a/lib/sata/link/test/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -MSCDIR = ../../../../ -PYTHON = python3 - -CMD = PYTHONPATH=$(MSCDIR) $(PYTHON) - -CC=gcc -CFLAGS =-Wall -O0 - -crc_tb: - $(CC) $(CFLAGS) $(INC) -o crc crc.c - $(CMD) crc_tb.py - -scrambler_tb: - $(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c - $(CMD) scrambler_tb.py - -link_tb: - $(CMD) link_tb.py - -all: crc_tb scrambler_tb - -clean: - rm crc scrambler *.vcd diff --git a/lib/sata/link/test/bfm.py b/lib/sata/link/test/bfm.py deleted file mode 100644 index f6791460..00000000 --- a/lib/sata/link/test/bfm.py +++ /dev/null @@ -1,308 +0,0 @@ -import subprocess - -from migen.fhdl.std import * - -from lib.sata.std import * -from lib.sata.link.test.common import * -from lib.sata.transport.std import * - -class PHYDword: - def __init__(self, dat=0): - self.dat = dat - self.start = 1 - self.done = 0 - -class PHYSource(Module): - def __init__(self): - self.source = Source(phy_layout(32)) - ### - self.dword = PHYDword() - - def send(self, dword): - self.dword = dword - - def do_simulation(self, selfp): - selfp.source.stb = 1 - selfp.source.charisk = 0b0000 - for k, v in primitives.items(): - if v == self.dword.dat: - selfp.source.charisk = 0b0001 - selfp.source.data = self.dword.dat - -class PHYSink(Module): - def __init__(self): - self.sink = Sink(phy_layout(32)) - ### - self.dword = PHYDword() - - def receive(self): - self.dword.done = 0 - while self.dword.done == 0: - yield - - def do_simulation(self, selfp): - self.dword.done = 0 - selfp.sink.ack = 1 - if selfp.sink.stb == 1: - self.dword.done = 1 - self.dword.dat = selfp.sink.data - -class PHYLayer(Module): - def __init__(self, debug): - self.debug = debug - - self.submodules.rx = PHYSink() - self.submodules.tx = PHYSource() - - self.source = self.tx.source - self.sink = self.rx.sink - - def send(self, dword): - packet = PHYDword(dword) - self.tx.send(packet) - - def receive(self): - yield from self.rx.receive() - if self.debug: - print(self) - - def __repr__(self): - receiving = "%08x " %self.rx.dword.dat - receiving += decode_primitive(self.rx.dword.dat) - receiving += " "*(16-len(receiving)) - - sending = "%08x " %self.tx.dword.dat - sending += decode_primitive(self.tx.dword.dat) - sending += " "*(16-len(sending)) - - return receiving + sending - -class LinkPacket(list): - def __init__(self): - self.ongoing = False - self.scrambled_datas = self.import_scrambler_datas() - - def import_scrambler_datas(self): - with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process: - process.stdin.write("0x10000".encode("ASCII")) - out, err = process.communicate() - return [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]] - -class LinkRXPacket(LinkPacket): - def decode(self): - self.descramble() - return self.check_crc() - - def descramble(self): - for i in range(len(self)): - self[i] = self[i] ^ self.scrambled_datas[i] - - def check_crc(self): - stdin = "" - for v in self[:-1]: - stdin += "0x%08x " %v - stdin += "exit" - with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process: - process.stdin.write(stdin.encode("ASCII")) - out, err = process.communicate() - crc = int(out.decode("ASCII"), 16) - r = (self[-1] == crc) - self.pop() - return r - -class LinkTXPacket(LinkPacket): - def encode(self): - self.scramble() - self.insert_crc() - - def scramble(self): - for i in range(len(self)): - self[i] = self[i] ^ self.scrambled_datas[i] - - def insert_crc(self): - stdin = "" - for v in self[:-1]: - stdin += "0x%08x " %v - stdin += "exit" - with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process: - process.stdin.write(stdin.encode("ASCII")) - out, err = process.communicate() - crc = int(out.decode("ASCII"), 16) - self.append(crc) - -class LinkLayer(Module): - def __init__(self, phy, debug, hold_random_level=0): - self.phy = phy - self.debug = debug - self.hold_random_level = hold_random_level - self.tx_packet = LinkTXPacket() - self.rx_packet = LinkRXPacket() - self.rx_cont = False - - self.transport_callback = None - - def set_transport_callback(self, callback): - self.transport_callback = callback - - def callback(self, dword): - if dword == primitives["CONT"]: - self.rx_cont = True - elif is_primitive(dword): - self.rx_cont = False - - if dword == primitives["X_RDY"]: - self.phy.send(primitives["R_RDY"]) - - elif dword == primitives["WTRM"]: - self.phy.send(primitives["R_OK"]) - - elif dword == primitives["HOLD"]: - self.phy.send(primitives["HOLDA"]) - - elif dword == primitives["EOF"]: - self.rx_packet.decode() - if self.transport_callback is not None: - self.transport_callback(self.rx_packet) - self.rx_packet.ongoing = False - - elif self.rx_packet.ongoing: - if dword != primitives["HOLD"]: - n = randn(100) - if n < self.hold_random_level: - self.phy.send(primitives["HOLD"]) - else: - self.phy.send(primitives["R_RDY"]) - if not is_primitive(dword): - if not self.rx_cont: - self.rx_packet.append(dword) - - elif dword == primitives["SOF"]: - self.rx_packet = LinkRXPacket() - self.rx_packet.ongoing = True - - def send(self, packet): - pass - - def gen_simulation(self, selfp): - self.phy.send(primitives["SYNC"]) - while True: - yield from self.phy.receive() - self.callback(self.phy.rx.dword.dat) - -def get_field_data(field, packet): - return (packet[field.dword] >> field.offset) & (2**field.width-1) - -class FIS: - def __init__(self, packet, layout): - self.packet = packet - self.layout = layout - self.decode() - - def decode(self): - for k, v in self.layout.items(): - setattr(self, k, get_field_data(v, self.packet)) - - def encode(self): - for k, v in self.layout.items(): - self.packet[v.dword] |= (getattr(self, k) << v.offset) - - def __repr__(self): - r = "--------\n" - for k in sorted(self.layout.keys()): - r += k + " : 0x%x" %getattr(self,k) + "\n" - return r - -class FIS_REG_H2D(FIS): - def __init__(self, packet=[0]*fis_reg_h2d_len): - FIS.__init__(self, packet,fis_reg_h2d_layout) - - def __repr__(self): - r = "FIS_REG_H2D\n" - r += FIS.__repr__(self) - return r - -class FIS_REG_D2H(FIS): - def __init__(self, packet=[0]*fis_reg_d2h_len): - FIS.__init__(self, packet,fis_reg_d2h_layout) - - def __repr__(self): - r = "FIS_REG_D2H\n" - r += FIS.__repr__(self) - return r - -class FIS_DMA_ACTIVATE_D2H(FIS): - def __init__(self, packet=[0]*fis_dma_activate_d2h_len): - FIS.__init__(self, packet,fis_dma_activate_d2h_layout) - - def __repr__(self): - r = "FIS_DMA_ACTIVATE_D2H\n" - r += FIS.__repr__(self) - return r - -class FIS_DMA_SETUP(FIS): - def __init__(self, packet=[0]*fis_dma_setup_len): - FIS.__init__(self, packet,fis_dma_setup_layout) - - def __repr__(self): - r = "FIS_DMA_SETUP\n" - r += FIS.__repr__(self) - return r - -class FIS_DATA(FIS): - def __init__(self, packet=[0]): - FIS.__init__(self, packet,fis_data_layout) - - def __repr__(self): - r = "FIS_DATA\n" - r += FIS.__repr__(self) - return r - -class FIS_PIO_SETUP_D2H(FIS): - def __init__(self, packet=[0]*fis_pio_setup_d2h_len): - FIS.__init__(self, packet,fis_pio_setup_d2h_layout) - - def __repr__(self): - r = "FIS_PIO_SETUP\n" - r += FIS.__repr__(self) - return r - -class FIS_UNKNOWN(FIS): - def __init__(self, packet=[0]): - FIS.__init__(self, packet, {}) - - def __repr__(self): - r = "UNKNOWN\n" - r += "--------\n" - for dword in self.packet: - r += "%08x\n" %dword - return r - -class TransportLayer(Module): - def __init__(self, link): - pass - - def callback(self, packet): - fis_type = packet[0] - if fis_type == fis_types["REG_H2D"]: - fis = FIS_REG_H2D(packet) - elif fis_type == fis_types["REG_D2H"]: - fis = FIS_REG_D2H(packet) - elif fis_type == fis_types["DMA_ACTIVATE_D2H"]: - fis = FIS_DMA_ACTIVATE_D2H(packet) - elif fis_type == fis_types["DMA_SETUP"]: - fis = FIS_SETUP(packet) - elif fis_type == fis_types["DATA"]: - fis = FIS_DATA(packet) - elif fis_type == fis_types["PIO_SETUP_D2H"]: - fis = FIS_PIO_SETUP_D2H(packet) - else: - fis = FIS_UNKNOWN(packet) - print(fis) - -class BFM(Module): - def __init__(self, dw, debug=False, hold_random_level=0): - ### - self.submodules.phy = PHYLayer(debug) - self.submodules.link = LinkLayer(self.phy, debug, hold_random_level) - self.submodules.transport = TransportLayer(self.link) - self.link.set_transport_callback(self.transport.callback) diff --git a/lib/sata/link/test/common.py b/lib/sata/link/test/common.py deleted file mode 100644 index 80986b44..00000000 --- a/lib/sata/link/test/common.py +++ /dev/null @@ -1,51 +0,0 @@ -import random - -from lib.sata.std import * - -def seed_to_data(seed, random=True): - if random: - return (seed * 0x31415979 + 1) & 0xffffffff - else: - return seed - -def check(ref, res): - 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 - -def randn(max_n): - return random.randint(0, max_n-1) - -class AckRandomizer(Module): - def __init__(self, description, level=0): - self.level = level - - self.sink = Sink(description) - self.source = Source(description) - - self.run = Signal() - - self.comb += \ - If(self.run, - Record.connect(self.sink, self.source) - ).Else( - self.source.stb.eq(0), - self.sink.ack.eq(0), - ) - - def do_simulation(self, selfp): - n = randn(100) - if n < self.level: - selfp.run = 0 - else: - selfp.run = 1 diff --git a/lib/sata/link/test/crc.c b/lib/sata/link/test/crc.c deleted file mode 100644 index 75576b5c..00000000 --- a/lib/sata/link/test/crc.c +++ /dev/null @@ -1,149 +0,0 @@ -// 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[]) -{ - int i; - unsigned int data_count; - unsigned int crc; - unsigned int data_in; - unsigned char crc_bit[32]; - unsigned char new_bit[32]; - - crc = 0x52325032; - data_count = 0; - - 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] ^ - crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[4]; - new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ - crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[3]; - new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ - crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[2]; - new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ - crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[1]; - new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ - crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^ - crc_bit[0]; - new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^ - crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[3] ^ crc_bit[2]; - new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^ - crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[2] ^ crc_bit[1]; - new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ - crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0]; - new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^ - crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[0]; - new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^ - crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[5]; - new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^ - crc_bit[16] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[4]; - new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^ - crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3]; - new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^ - crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2]; - new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^ - crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[1]; - new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ - crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[0]; - new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^ - crc_bit[15] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ - crc_bit[3]; - new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^ - crc_bit[14] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^ - crc_bit[2]; - new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^ - crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[3] ^ - crc_bit[2] ^ crc_bit[1]; - new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^ - crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ - crc_bit[2] ^ crc_bit[1] ^ crc_bit[0]; - new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ - crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[4] ^ - crc_bit[3] ^ crc_bit[1] ^ crc_bit[0]; - new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^ - crc_bit[13] ^ crc_bit[9] ^ crc_bit[5] ^ crc_bit[3] ^ crc_bit[2] ^ crc_bit[0]; - new_bit[9] = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^ - crc_bit[9] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ crc_bit[1]; - new_bit[8] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^ - crc_bit[10] ^ crc_bit[8] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ crc_bit[0]; - new_bit[7] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^ - crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[3] ^ - crc_bit[2] ^ crc_bit[0]; - new_bit[6] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^ - crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ - crc_bit[1]; - new_bit[5] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^ - crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ - crc_bit[0]; - new_bit[4] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^ - crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[4] ^ - crc_bit[3] ^ crc_bit[2] ^ crc_bit[0]; - new_bit[3] = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^ - crc_bit[14] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3] ^ crc_bit[2] ^ - crc_bit[1]; - new_bit[2] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^ - crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2] ^ - crc_bit[1] ^ crc_bit[0]; - new_bit[1] = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^ - crc_bit[11] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0]; - 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); - return 0; -} diff --git a/lib/sata/link/test/crc_tb.py b/lib/sata/link/test/crc_tb.py deleted file mode 100644 index a4bd51bb..00000000 --- a/lib/sata/link/test/crc_tb.py +++ /dev/null @@ -1,60 +0,0 @@ -import subprocess - -from migen.fhdl.std import * - -from lib.sata.std import * -from lib.sata.link.crc import * -from lib.sata.link.test.common import * - -class TB(Module): - 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("ASCII")) - out, err = process.communicate() - return int(out.decode("ASCII"), 16) - - def gen_simulation(self, selfp): - # init CRC - selfp.crc.d = 0 - selfp.crc.ce = 1 - selfp.crc.reset = 1 - yield - selfp.crc.reset = 0 - - # feed CRC with datas - datas = [] - for i in range(self.length): - data = seed_to_data(i, self.random) - datas.append(data) - selfp.crc.d = data - 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 - 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, True), ncycles=length+100, vcd_name="my.vcd") diff --git a/lib/sata/link/test/link_tb.py b/lib/sata/link/test/link_tb.py deleted file mode 100644 index 5a7d4aa9..00000000 --- a/lib/sata/link/test/link_tb.py +++ /dev/null @@ -1,96 +0,0 @@ -import random - -from migen.fhdl.std import * -from migen.genlib.record import * -from migen.sim.generic import run_simulation - -from lib.sata.std import * -from lib.sata.link import SATALinkLayer - -from lib.sata.link.test.bfm import * -from lib.sata.link.test.common import * - -class LinkPacket(): - def __init__(self, d=[]): - self.d = d - self.start = 1 - self.done = 0 - -class LinkStreamer(Module): - def __init__(self, dw): - self.source = Source(link_layout(dw)) - ### - self.packets = [] - self.packet = LinkPacket() - self.packet.done = 1 - - def send(self, packet, blocking=True): - self.packets.append(packet) - if blocking: - while packet.done == 0: - yield - - def do_simulation(self, selfp): - if len(self.packets) and self.packet.done: - self.packet = self.packets.pop(0) - if self.packet.start and not self.packet.done: - selfp.source.stb = 1 - selfp.source.sop = 1 - selfp.source.d = self.packet.d.pop(0) - self.packet.start = 0 - elif selfp.source.stb == 1 and selfp.source.ack == 1: - selfp.source.sop = 0 - selfp.source.eop = (len(self.packet.d) == 1) - if len(self.packet.d) > 0: - selfp.source.stb = 1 - selfp.source.d = self.packet.d.pop(0) - else: - self.packet.done = 1 - selfp.source.stb = 0 - -class LinkLogger(Module): - def __init__(self, dw): - self.sink = Sink(link_layout(dw)) - ### - self.packet = LinkPacket() - - def receive(self): - self.packet.done = 0 - while self.packet.done == 0: - yield - - def do_simulation(self, selfp): - self.packet.done = 0 - selfp.sink.ack = 1 - if selfp.sink.stb == 1 and selfp.sink.sop == 1: - self.packet.start = 1 - self.packet.d = [selfp.sink.d] - elif selfp.sink.stb: - self.packet.start = 0 - self.packet.d.append(selfp.sink.d) - if (selfp.sink.stb ==1 and selfp.sink.eop ==1): - self.packet.done = 1 - -class TB(Module): - def __init__(self): - self.submodules.bfm = BFM(32, debug=True, hold_random_level=50) - self.submodules.link_layer = SATALinkLayer(self.bfm.phy) - - self.submodules.streamer = LinkStreamer(32) - streamer_ack_randomizer = AckRandomizer(link_layout(32), level=50) - self.submodules += streamer_ack_randomizer - self.submodules.logger = LinkLogger(32) - self.comb += [ - Record.connect(self.streamer.source, streamer_ack_randomizer.sink), - Record.connect(streamer_ack_randomizer.source, self.link_layer.sink), - Record.connect(self.link_layer.source, self.logger.sink) - ] - - def gen_simulation(self, selfp): - for i in range(200): - yield - for i in range(8): - yield from self.streamer.send(LinkPacket([i for i in range(16)])) - -if __name__ == "__main__": - run_simulation(TB(), ncycles=512, vcd_name="my.vcd", keep_files=True) diff --git a/lib/sata/link/test/scrambler.c b/lib/sata/link/test/scrambler.c deleted file mode 100644 index cee4b30a..00000000 --- a/lib/sata/link/test/scrambler.c +++ /dev/null @@ -1,113 +0,0 @@ -// Adapted from SATA specification -/****************************************************************************/ -/* */ -/* scramble.c */ -/* */ -/* This sample code generates the entire sequence of 65535 Dwords produced */ -/* by the scrambler defined in the Serial ATA specification. The */ -/* specification calls for an LFSR to generate a string of bits that will */ -/* be packaged into 32 bit Dwords to be XORed with the data Dwords. The */ -/* generator polynomial specified is: */ -/* 16 15 13 4 */ -/* G(x) = x + x + x + x + 1 */ -/* */ -/* Parallelized versions of the scrambler are initialized to a value */ -/* derived from the initialization value of 0xFFFF defined in the */ -/* specification. This implementation is initialized to 0xF0F6. Other */ -/* parallel implementations will have different initial values. The */ -/* important point is that the first Dword output of any implementation */ -/* must equal 0xC2D2768D. */ -/* This code does not represent an elegant solution for a C implementation, */ -/* but it does demonstrate a method of generating the sequence that can be */ -/* easily implemented in hardware. A block diagram of the circuit emulated */ -/* by this code is shown below. */ -/* */ -/* +-----------------------------------+ */ -/* | | */ -/* | | */ -/* | +---+ +---+ | */ -/* | | R | | * | | */ -/* +---->| e |----------+---->| M |----+----> Output(31 downto 16) */ -/* | g | | | 1 | */ -/* +---+ | +---+ */ -/* | */ -/* | +---+ */ -/* | | * | */ -/* +---->| M |---------> Output(15 downto 0) */ -/* | 2 | */ -/* +---+ */ -/* */ -/* The register shown in the block diagram is a 16 bit register. The two */ -/* boxes, *M1 and *M2, each represent a multiply by a 16 by 16 binary */ -/* matrix. A 16 by 16 matrix times a 16 bit vector yields a 16 bit vector. */ -/* The two vectors are the two halves of the 32 bit scrambler value. The */ -/* upper half of the scrambler value is stored back into the context */ -/* register to be used to generate the next value in the scrambler */ -/* */ -/****************************************************************************/ -#include -#include -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; - - scanf("0x%8x", &length); - - for (i = 0; i < length; ++i) { - for (j = 0; j < 16; ++j) { - now[j] = (context >> j) & 0x01; - } - next[31] = now[12] ^ now[10] ^ now[7] ^ now[3] ^ now[1] ^ now[0]; - next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9] ^ now[6] ^ now[3] ^ now[2] ^ now[0]; - next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[5] ^ now[3] ^ now[2] ^ now[1]; - next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[4] ^ now[2] ^ now[1] ^ now[0]; - next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[1] ^ now[0]; - next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[0]; - next[25] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[3] ^ now[2]; - next[24] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1]; - next[23] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0]; - next[22] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[1] ^ now[0]; - next[21] = now[15] ^ now[13] ^ now[12] ^ now[6] ^ now[5] ^ now[4] ^ now[0]; - next[20] = now[15] ^ now[11] ^ now[5] ^ now[4]; - next[19] = now[14] ^ now[10] ^ now[4] ^ now[3]; - next[18] = now[13] ^ now[9] ^ now[3] ^ now[2]; - next[17] = now[12] ^ now[8] ^ now[2] ^ now[1]; - next[16] = now[11] ^ now[7] ^ now[1] ^ now[0]; - - - next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6] ^ now[3] ^ now[0]; - next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9] ^ now[5] ^ now[3] ^ now[2]; - next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[4] ^ now[2] ^ now[1]; - next[12] = now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[3] ^ now[1] ^ now[0]; - next[11] = now[15] ^ now[14] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[3] ^ now[2] ^ now[0]; - next[10] = now[15] ^ now[13] ^ now[12] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[2] ^ now[1]; - next[9] = now[14] ^ now[12] ^ now[11] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[2] ^ now[1] ^ now[0]; - next[8] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7] ^ now[6] ^ now[5] ^ now[1] ^ now[0]; - next[7] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[6] ^ now[5] ^ now[4] ^ now[3] ^ now[0]; - next[6] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[5] ^ now[4] ^ now[2]; - next[5] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[4] ^ now[3] ^ now[1]; - next[4] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[3] ^ now[2] ^ now[0]; - next[3] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1]; - next[2] = now[14] ^ now[13] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0]; - next[1] = now[15] ^ now[14] ^ now[13] ^ now[5] ^ now[4] ^ now[1] ^ now[0]; - next[0] = now[15] ^ now[13] ^ now[4] ^ now[0]; - - scrambler = 0; - for (j = 31; j >= 0; --j) { - scrambler = scrambler << 1; - scrambler |= next[j]; - } - context = scrambler >> 16; - printf("%08x\n", (unsigned int) scrambler); - - } - - return 0; - -} \ No newline at end of file diff --git a/lib/sata/link/test/scrambler_tb.py b/lib/sata/link/test/scrambler_tb.py deleted file mode 100644 index 9f2ad8d6..00000000 --- a/lib/sata/link/test/scrambler_tb.py +++ /dev/null @@ -1,50 +0,0 @@ -import subprocess - -from migen.fhdl.std import * - -from lib.sata.std import * -from lib.sata.link.scrambler import * -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("ASCII")) - out, err = process.communicate() - return [int(e, 16) for e in out.decode("ASCII").split("\n")[:-1]] - - def gen_simulation(self, selfp): - # init CRC - selfp.scrambler.ce = 1 - selfp.scrambler.reset = 1 - yield - selfp.scrambler.reset = 0 - - # log results - yield - sim_values = [] - for i in range(self.length): - sim_values.append(selfp.scrambler.value) - 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 - 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") diff --git a/lib/sata/test/Makefile b/lib/sata/test/Makefile new file mode 100644 index 00000000..abb4d605 --- /dev/null +++ b/lib/sata/test/Makefile @@ -0,0 +1,23 @@ +MSCDIR = ../../../ +PYTHON = python3 + +CMD = PYTHONPATH=$(MSCDIR) $(PYTHON) + +CC=gcc +CFLAGS =-Wall -O0 + +crc_tb: + $(CC) $(CFLAGS) $(INC) -o crc crc.c + $(CMD) crc_tb.py + +scrambler_tb: + $(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c + $(CMD) scrambler_tb.py + +link_tb: + $(CMD) link_tb.py + +all: crc_tb scrambler_tb + +clean: + rm crc scrambler *.vcd diff --git a/lib/sata/test/bfm.py b/lib/sata/test/bfm.py new file mode 100644 index 00000000..af7a2685 --- /dev/null +++ b/lib/sata/test/bfm.py @@ -0,0 +1,309 @@ +import subprocess + +from migen.fhdl.std import * + +from lib.sata.std import * +from lib.sata.transport.std import * + +from lib.sata.test.common import * + +class PHYDword: + def __init__(self, dat=0): + self.dat = dat + self.start = 1 + self.done = 0 + +class PHYSource(Module): + def __init__(self): + self.source = Source(phy_layout(32)) + ### + self.dword = PHYDword() + + def send(self, dword): + self.dword = dword + + def do_simulation(self, selfp): + selfp.source.stb = 1 + selfp.source.charisk = 0b0000 + for k, v in primitives.items(): + if v == self.dword.dat: + selfp.source.charisk = 0b0001 + selfp.source.data = self.dword.dat + +class PHYSink(Module): + def __init__(self): + self.sink = Sink(phy_layout(32)) + ### + self.dword = PHYDword() + + def receive(self): + self.dword.done = 0 + while self.dword.done == 0: + yield + + def do_simulation(self, selfp): + self.dword.done = 0 + selfp.sink.ack = 1 + if selfp.sink.stb == 1: + self.dword.done = 1 + self.dword.dat = selfp.sink.data + +class PHYLayer(Module): + def __init__(self, debug): + self.debug = debug + + self.submodules.rx = PHYSink() + self.submodules.tx = PHYSource() + + self.source = self.tx.source + self.sink = self.rx.sink + + def send(self, dword): + packet = PHYDword(dword) + self.tx.send(packet) + + def receive(self): + yield from self.rx.receive() + if self.debug: + print(self) + + def __repr__(self): + receiving = "%08x " %self.rx.dword.dat + receiving += decode_primitive(self.rx.dword.dat) + receiving += " "*(16-len(receiving)) + + sending = "%08x " %self.tx.dword.dat + sending += decode_primitive(self.tx.dword.dat) + sending += " "*(16-len(sending)) + + return receiving + sending + +class LinkPacket(list): + def __init__(self): + self.ongoing = False + self.scrambled_datas = self.import_scrambler_datas() + + def import_scrambler_datas(self): + with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process: + process.stdin.write("0x10000".encode("ASCII")) + out, err = process.communicate() + return [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]] + +class LinkRXPacket(LinkPacket): + def decode(self): + self.descramble() + return self.check_crc() + + def descramble(self): + for i in range(len(self)): + self[i] = self[i] ^ self.scrambled_datas[i] + + def check_crc(self): + stdin = "" + for v in self[:-1]: + stdin += "0x%08x " %v + stdin += "exit" + with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process: + process.stdin.write(stdin.encode("ASCII")) + out, err = process.communicate() + crc = int(out.decode("ASCII"), 16) + r = (self[-1] == crc) + self.pop() + return r + +class LinkTXPacket(LinkPacket): + def encode(self): + self.scramble() + self.insert_crc() + + def scramble(self): + for i in range(len(self)): + self[i] = self[i] ^ self.scrambled_datas[i] + + def insert_crc(self): + stdin = "" + for v in self[:-1]: + stdin += "0x%08x " %v + stdin += "exit" + with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process: + process.stdin.write(stdin.encode("ASCII")) + out, err = process.communicate() + crc = int(out.decode("ASCII"), 16) + self.append(crc) + +class LinkLayer(Module): + def __init__(self, phy, debug, hold_random_level=0): + self.phy = phy + self.debug = debug + self.hold_random_level = hold_random_level + self.tx_packet = LinkTXPacket() + self.rx_packet = LinkRXPacket() + self.rx_cont = False + + self.transport_callback = None + + def set_transport_callback(self, callback): + self.transport_callback = callback + + def callback(self, dword): + if dword == primitives["CONT"]: + self.rx_cont = True + elif is_primitive(dword): + self.rx_cont = False + + if dword == primitives["X_RDY"]: + self.phy.send(primitives["R_RDY"]) + + elif dword == primitives["WTRM"]: + self.phy.send(primitives["R_OK"]) + + elif dword == primitives["HOLD"]: + self.phy.send(primitives["HOLDA"]) + + elif dword == primitives["EOF"]: + self.rx_packet.decode() + if self.transport_callback is not None: + self.transport_callback(self.rx_packet) + self.rx_packet.ongoing = False + + elif self.rx_packet.ongoing: + if dword != primitives["HOLD"]: + n = randn(100) + if n < self.hold_random_level: + self.phy.send(primitives["HOLD"]) + else: + self.phy.send(primitives["R_RDY"]) + if not is_primitive(dword): + if not self.rx_cont: + self.rx_packet.append(dword) + + elif dword == primitives["SOF"]: + self.rx_packet = LinkRXPacket() + self.rx_packet.ongoing = True + + def send(self, packet): + pass + + def gen_simulation(self, selfp): + self.phy.send(primitives["SYNC"]) + while True: + yield from self.phy.receive() + self.callback(self.phy.rx.dword.dat) + +def get_field_data(field, packet): + return (packet[field.dword] >> field.offset) & (2**field.width-1) + +class FIS: + def __init__(self, packet, layout): + self.packet = packet + self.layout = layout + self.decode() + + def decode(self): + for k, v in self.layout.items(): + setattr(self, k, get_field_data(v, self.packet)) + + def encode(self): + for k, v in self.layout.items(): + self.packet[v.dword] |= (getattr(self, k) << v.offset) + + def __repr__(self): + r = "--------\n" + for k in sorted(self.layout.keys()): + r += k + " : 0x%x" %getattr(self,k) + "\n" + return r + +class FIS_REG_H2D(FIS): + def __init__(self, packet=[0]*fis_reg_h2d_len): + FIS.__init__(self, packet,fis_reg_h2d_layout) + + def __repr__(self): + r = "FIS_REG_H2D\n" + r += FIS.__repr__(self) + return r + +class FIS_REG_D2H(FIS): + def __init__(self, packet=[0]*fis_reg_d2h_len): + FIS.__init__(self, packet,fis_reg_d2h_layout) + + def __repr__(self): + r = "FIS_REG_D2H\n" + r += FIS.__repr__(self) + return r + +class FIS_DMA_ACTIVATE_D2H(FIS): + def __init__(self, packet=[0]*fis_dma_activate_d2h_len): + FIS.__init__(self, packet,fis_dma_activate_d2h_layout) + + def __repr__(self): + r = "FIS_DMA_ACTIVATE_D2H\n" + r += FIS.__repr__(self) + return r + +class FIS_DMA_SETUP(FIS): + def __init__(self, packet=[0]*fis_dma_setup_len): + FIS.__init__(self, packet,fis_dma_setup_layout) + + def __repr__(self): + r = "FIS_DMA_SETUP\n" + r += FIS.__repr__(self) + return r + +class FIS_DATA(FIS): + def __init__(self, packet=[0]): + FIS.__init__(self, packet,fis_data_layout) + + def __repr__(self): + r = "FIS_DATA\n" + r += FIS.__repr__(self) + return r + +class FIS_PIO_SETUP_D2H(FIS): + def __init__(self, packet=[0]*fis_pio_setup_d2h_len): + FIS.__init__(self, packet,fis_pio_setup_d2h_layout) + + def __repr__(self): + r = "FIS_PIO_SETUP\n" + r += FIS.__repr__(self) + return r + +class FIS_UNKNOWN(FIS): + def __init__(self, packet=[0]): + FIS.__init__(self, packet, {}) + + def __repr__(self): + r = "UNKNOWN\n" + r += "--------\n" + for dword in self.packet: + r += "%08x\n" %dword + return r + +class TransportLayer(Module): + def __init__(self, link): + pass + + def callback(self, packet): + fis_type = packet[0] + if fis_type == fis_types["REG_H2D"]: + fis = FIS_REG_H2D(packet) + elif fis_type == fis_types["REG_D2H"]: + fis = FIS_REG_D2H(packet) + elif fis_type == fis_types["DMA_ACTIVATE_D2H"]: + fis = FIS_DMA_ACTIVATE_D2H(packet) + elif fis_type == fis_types["DMA_SETUP"]: + fis = FIS_SETUP(packet) + elif fis_type == fis_types["DATA"]: + fis = FIS_DATA(packet) + elif fis_type == fis_types["PIO_SETUP_D2H"]: + fis = FIS_PIO_SETUP_D2H(packet) + else: + fis = FIS_UNKNOWN(packet) + print(fis) + +class BFM(Module): + def __init__(self, dw, debug=False, hold_random_level=0): + ### + self.submodules.phy = PHYLayer(debug) + self.submodules.link = LinkLayer(self.phy, debug, hold_random_level) + self.submodules.transport = TransportLayer(self.link) + self.link.set_transport_callback(self.transport.callback) diff --git a/lib/sata/test/common.py b/lib/sata/test/common.py new file mode 100644 index 00000000..80986b44 --- /dev/null +++ b/lib/sata/test/common.py @@ -0,0 +1,51 @@ +import random + +from lib.sata.std import * + +def seed_to_data(seed, random=True): + if random: + return (seed * 0x31415979 + 1) & 0xffffffff + else: + return seed + +def check(ref, res): + 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 + +def randn(max_n): + return random.randint(0, max_n-1) + +class AckRandomizer(Module): + def __init__(self, description, level=0): + self.level = level + + self.sink = Sink(description) + self.source = Source(description) + + self.run = Signal() + + self.comb += \ + If(self.run, + Record.connect(self.sink, self.source) + ).Else( + self.source.stb.eq(0), + self.sink.ack.eq(0), + ) + + def do_simulation(self, selfp): + n = randn(100) + if n < self.level: + selfp.run = 0 + else: + selfp.run = 1 diff --git a/lib/sata/test/crc.c b/lib/sata/test/crc.c new file mode 100644 index 00000000..75576b5c --- /dev/null +++ b/lib/sata/test/crc.c @@ -0,0 +1,149 @@ +// 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[]) +{ + int i; + unsigned int data_count; + unsigned int crc; + unsigned int data_in; + unsigned char crc_bit[32]; + unsigned char new_bit[32]; + + crc = 0x52325032; + data_count = 0; + + 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] ^ + crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[4]; + new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ + crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[3]; + new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ + crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[2]; + new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ + crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[1]; + new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ + crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^ + crc_bit[0]; + new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^ + crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[3] ^ crc_bit[2]; + new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^ + crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[2] ^ crc_bit[1]; + new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ + crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0]; + new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^ + crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[0]; + new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^ + crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[5]; + new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^ + crc_bit[16] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[4]; + new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^ + crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3]; + new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^ + crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2]; + new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^ + crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[1]; + new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ + crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[0]; + new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^ + crc_bit[15] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ + crc_bit[3]; + new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^ + crc_bit[14] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^ + crc_bit[2]; + new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^ + crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[3] ^ + crc_bit[2] ^ crc_bit[1]; + new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^ + crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ + crc_bit[2] ^ crc_bit[1] ^ crc_bit[0]; + new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ + crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[4] ^ + crc_bit[3] ^ crc_bit[1] ^ crc_bit[0]; + new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^ + crc_bit[13] ^ crc_bit[9] ^ crc_bit[5] ^ crc_bit[3] ^ crc_bit[2] ^ crc_bit[0]; + new_bit[9] = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^ + crc_bit[9] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ crc_bit[1]; + new_bit[8] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^ + crc_bit[10] ^ crc_bit[8] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ crc_bit[0]; + new_bit[7] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^ + crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[3] ^ + crc_bit[2] ^ crc_bit[0]; + new_bit[6] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^ + crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ + crc_bit[1]; + new_bit[5] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^ + crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ + crc_bit[0]; + new_bit[4] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^ + crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[4] ^ + crc_bit[3] ^ crc_bit[2] ^ crc_bit[0]; + new_bit[3] = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^ + crc_bit[14] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3] ^ crc_bit[2] ^ + crc_bit[1]; + new_bit[2] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^ + crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2] ^ + crc_bit[1] ^ crc_bit[0]; + new_bit[1] = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^ + crc_bit[11] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0]; + 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); + return 0; +} diff --git a/lib/sata/test/crc_tb.py b/lib/sata/test/crc_tb.py new file mode 100644 index 00000000..0ce17dca --- /dev/null +++ b/lib/sata/test/crc_tb.py @@ -0,0 +1,61 @@ +import subprocess + +from migen.fhdl.std import * + +from lib.sata.std import * +from lib.sata.link.crc import * + +from lib.sata.test.common import * + +class TB(Module): + 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("ASCII")) + out, err = process.communicate() + return int(out.decode("ASCII"), 16) + + def gen_simulation(self, selfp): + # init CRC + selfp.crc.d = 0 + selfp.crc.ce = 1 + selfp.crc.reset = 1 + yield + selfp.crc.reset = 0 + + # feed CRC with datas + datas = [] + for i in range(self.length): + data = seed_to_data(i, self.random) + datas.append(data) + selfp.crc.d = data + 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 + 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, True), ncycles=length+100, vcd_name="my.vcd") diff --git a/lib/sata/test/link_tb.py b/lib/sata/test/link_tb.py new file mode 100644 index 00000000..3260034f --- /dev/null +++ b/lib/sata/test/link_tb.py @@ -0,0 +1,96 @@ +import random + +from migen.fhdl.std import * +from migen.genlib.record import * +from migen.sim.generic import run_simulation + +from lib.sata.std import * +from lib.sata.link import SATALinkLayer + +from lib.sata.test.bfm import * +from lib.sata.test.common import * + +class LinkPacket(): + def __init__(self, d=[]): + self.d = d + self.start = 1 + self.done = 0 + +class LinkStreamer(Module): + def __init__(self, dw): + self.source = Source(link_layout(dw)) + ### + self.packets = [] + self.packet = LinkPacket() + self.packet.done = 1 + + def send(self, packet, blocking=True): + self.packets.append(packet) + if blocking: + while packet.done == 0: + yield + + def do_simulation(self, selfp): + if len(self.packets) and self.packet.done: + self.packet = self.packets.pop(0) + if self.packet.start and not self.packet.done: + selfp.source.stb = 1 + selfp.source.sop = 1 + selfp.source.d = self.packet.d.pop(0) + self.packet.start = 0 + elif selfp.source.stb == 1 and selfp.source.ack == 1: + selfp.source.sop = 0 + selfp.source.eop = (len(self.packet.d) == 1) + if len(self.packet.d) > 0: + selfp.source.stb = 1 + selfp.source.d = self.packet.d.pop(0) + else: + self.packet.done = 1 + selfp.source.stb = 0 + +class LinkLogger(Module): + def __init__(self, dw): + self.sink = Sink(link_layout(dw)) + ### + self.packet = LinkPacket() + + def receive(self): + self.packet.done = 0 + while self.packet.done == 0: + yield + + def do_simulation(self, selfp): + self.packet.done = 0 + selfp.sink.ack = 1 + if selfp.sink.stb == 1 and selfp.sink.sop == 1: + self.packet.start = 1 + self.packet.d = [selfp.sink.d] + elif selfp.sink.stb: + self.packet.start = 0 + self.packet.d.append(selfp.sink.d) + if (selfp.sink.stb ==1 and selfp.sink.eop ==1): + self.packet.done = 1 + +class TB(Module): + def __init__(self): + self.submodules.bfm = BFM(32, debug=True, hold_random_level=50) + self.submodules.link_layer = SATALinkLayer(self.bfm.phy) + + self.submodules.streamer = LinkStreamer(32) + streamer_ack_randomizer = AckRandomizer(link_layout(32), level=50) + self.submodules += streamer_ack_randomizer + self.submodules.logger = LinkLogger(32) + self.comb += [ + Record.connect(self.streamer.source, streamer_ack_randomizer.sink), + Record.connect(streamer_ack_randomizer.source, self.link_layer.sink), + Record.connect(self.link_layer.source, self.logger.sink) + ] + + def gen_simulation(self, selfp): + for i in range(200): + yield + for i in range(8): + yield from self.streamer.send(LinkPacket([i for i in range(16)])) + +if __name__ == "__main__": + run_simulation(TB(), ncycles=512, vcd_name="my.vcd", keep_files=True) diff --git a/lib/sata/test/scrambler.c b/lib/sata/test/scrambler.c new file mode 100644 index 00000000..cee4b30a --- /dev/null +++ b/lib/sata/test/scrambler.c @@ -0,0 +1,113 @@ +// Adapted from SATA specification +/****************************************************************************/ +/* */ +/* scramble.c */ +/* */ +/* This sample code generates the entire sequence of 65535 Dwords produced */ +/* by the scrambler defined in the Serial ATA specification. The */ +/* specification calls for an LFSR to generate a string of bits that will */ +/* be packaged into 32 bit Dwords to be XORed with the data Dwords. The */ +/* generator polynomial specified is: */ +/* 16 15 13 4 */ +/* G(x) = x + x + x + x + 1 */ +/* */ +/* Parallelized versions of the scrambler are initialized to a value */ +/* derived from the initialization value of 0xFFFF defined in the */ +/* specification. This implementation is initialized to 0xF0F6. Other */ +/* parallel implementations will have different initial values. The */ +/* important point is that the first Dword output of any implementation */ +/* must equal 0xC2D2768D. */ +/* This code does not represent an elegant solution for a C implementation, */ +/* but it does demonstrate a method of generating the sequence that can be */ +/* easily implemented in hardware. A block diagram of the circuit emulated */ +/* by this code is shown below. */ +/* */ +/* +-----------------------------------+ */ +/* | | */ +/* | | */ +/* | +---+ +---+ | */ +/* | | R | | * | | */ +/* +---->| e |----------+---->| M |----+----> Output(31 downto 16) */ +/* | g | | | 1 | */ +/* +---+ | +---+ */ +/* | */ +/* | +---+ */ +/* | | * | */ +/* +---->| M |---------> Output(15 downto 0) */ +/* | 2 | */ +/* +---+ */ +/* */ +/* The register shown in the block diagram is a 16 bit register. The two */ +/* boxes, *M1 and *M2, each represent a multiply by a 16 by 16 binary */ +/* matrix. A 16 by 16 matrix times a 16 bit vector yields a 16 bit vector. */ +/* The two vectors are the two halves of the 32 bit scrambler value. The */ +/* upper half of the scrambler value is stored back into the context */ +/* register to be used to generate the next value in the scrambler */ +/* */ +/****************************************************************************/ +#include +#include +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; + + scanf("0x%8x", &length); + + for (i = 0; i < length; ++i) { + for (j = 0; j < 16; ++j) { + now[j] = (context >> j) & 0x01; + } + next[31] = now[12] ^ now[10] ^ now[7] ^ now[3] ^ now[1] ^ now[0]; + next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9] ^ now[6] ^ now[3] ^ now[2] ^ now[0]; + next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[5] ^ now[3] ^ now[2] ^ now[1]; + next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[4] ^ now[2] ^ now[1] ^ now[0]; + next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[1] ^ now[0]; + next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[0]; + next[25] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[3] ^ now[2]; + next[24] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1]; + next[23] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0]; + next[22] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[1] ^ now[0]; + next[21] = now[15] ^ now[13] ^ now[12] ^ now[6] ^ now[5] ^ now[4] ^ now[0]; + next[20] = now[15] ^ now[11] ^ now[5] ^ now[4]; + next[19] = now[14] ^ now[10] ^ now[4] ^ now[3]; + next[18] = now[13] ^ now[9] ^ now[3] ^ now[2]; + next[17] = now[12] ^ now[8] ^ now[2] ^ now[1]; + next[16] = now[11] ^ now[7] ^ now[1] ^ now[0]; + + + next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6] ^ now[3] ^ now[0]; + next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9] ^ now[5] ^ now[3] ^ now[2]; + next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[4] ^ now[2] ^ now[1]; + next[12] = now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[3] ^ now[1] ^ now[0]; + next[11] = now[15] ^ now[14] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[3] ^ now[2] ^ now[0]; + next[10] = now[15] ^ now[13] ^ now[12] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[2] ^ now[1]; + next[9] = now[14] ^ now[12] ^ now[11] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[2] ^ now[1] ^ now[0]; + next[8] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7] ^ now[6] ^ now[5] ^ now[1] ^ now[0]; + next[7] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[6] ^ now[5] ^ now[4] ^ now[3] ^ now[0]; + next[6] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[5] ^ now[4] ^ now[2]; + next[5] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[4] ^ now[3] ^ now[1]; + next[4] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[3] ^ now[2] ^ now[0]; + next[3] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1]; + next[2] = now[14] ^ now[13] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0]; + next[1] = now[15] ^ now[14] ^ now[13] ^ now[5] ^ now[4] ^ now[1] ^ now[0]; + next[0] = now[15] ^ now[13] ^ now[4] ^ now[0]; + + scrambler = 0; + for (j = 31; j >= 0; --j) { + scrambler = scrambler << 1; + scrambler |= next[j]; + } + context = scrambler >> 16; + printf("%08x\n", (unsigned int) scrambler); + + } + + return 0; + +} \ No newline at end of file diff --git a/lib/sata/test/scrambler_tb.py b/lib/sata/test/scrambler_tb.py new file mode 100644 index 00000000..3100dc9f --- /dev/null +++ b/lib/sata/test/scrambler_tb.py @@ -0,0 +1,51 @@ +import subprocess + +from migen.fhdl.std import * + +from lib.sata.std import * +from lib.sata.link.scrambler import * + +from lib.sata.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("ASCII")) + out, err = process.communicate() + return [int(e, 16) for e in out.decode("ASCII").split("\n")[:-1]] + + def gen_simulation(self, selfp): + # init CRC + selfp.scrambler.ce = 1 + selfp.scrambler.reset = 1 + yield + selfp.scrambler.reset = 0 + + # log results + yield + sim_values = [] + for i in range(self.length): + sim_values.append(selfp.scrambler.value) + 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 + 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")