+++ /dev/null
-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
+++ /dev/null
-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)
+++ /dev/null
-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
+++ /dev/null
-// Adapted from SATA specification
-/****************************************************************************/
-/* */
-/* crc.c */
-/* */
-/* This sample code reads standard in for a sequence of 32 bit values */
-/* formatted in hexadecimal with a leading "0x" (e.g. 0xDEADBEEF). The */
-/* code calculates the Serial ATA CRC for the input data stream. The */
-/* generator polynomial used is: */
-/* 32 26 23 22 16 12 11 10 8 7 5 4 2 */
-/* G(x) = x + x + x + x + x + x + x + x + x + x + x + x + x + x + 1 */
-/* */
-/* This sample code uses a parallel implementation of the CRC calculation */
-/* circuit that is suitable for implementation in hardware. A block */
-/* diagram of the circuit being emulated is shown below. */
-/* */
-/* +---+ +---+ +---+ */
-/* Data_In --------->| | | | | R | */
-/* | + |--------->| * |--------->| e |----+ */
-/* +---->| | | | | g | | */
-/* | +---+ +---+ +---+ | */
-/* | | */
-/* | | */
-/* +--------------------------------------------+ */
-/* */
-/* The CRC value is initialized to 0x52325032 as defined in the Serial ATA */
-/* specification. */
-/* */
-/****************************************************************************/
-
-
-
-#include <stdlib.h>
-#include <stdio.h>
-int main(int argc, char *argv[])
-{
- 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;
-}
+++ /dev/null
-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")
+++ /dev/null
-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)
+++ /dev/null
-// 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 <stdlib.h>
-#include <stdio.h>
-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
+++ /dev/null
-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")
--- /dev/null
+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
--- /dev/null
+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)
--- /dev/null
+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
--- /dev/null
+// Adapted from SATA specification
+/****************************************************************************/
+/* */
+/* crc.c */
+/* */
+/* This sample code reads standard in for a sequence of 32 bit values */
+/* formatted in hexadecimal with a leading "0x" (e.g. 0xDEADBEEF). The */
+/* code calculates the Serial ATA CRC for the input data stream. The */
+/* generator polynomial used is: */
+/* 32 26 23 22 16 12 11 10 8 7 5 4 2 */
+/* G(x) = x + x + x + x + x + x + x + x + x + x + x + x + x + x + 1 */
+/* */
+/* This sample code uses a parallel implementation of the CRC calculation */
+/* circuit that is suitable for implementation in hardware. A block */
+/* diagram of the circuit being emulated is shown below. */
+/* */
+/* +---+ +---+ +---+ */
+/* Data_In --------->| | | | | R | */
+/* | + |--------->| * |--------->| e |----+ */
+/* +---->| | | | | g | | */
+/* | +---+ +---+ +---+ | */
+/* | | */
+/* | | */
+/* +--------------------------------------------+ */
+/* */
+/* The CRC value is initialized to 0x52325032 as defined in the Serial ATA */
+/* specification. */
+/* */
+/****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <stdio.h>
+int main(int argc, char *argv[])
+{
+ 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;
+}
--- /dev/null
+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")
--- /dev/null
+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)
--- /dev/null
+// 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 <stdlib.h>
+#include <stdio.h>
+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
--- /dev/null
+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")