link: test RX path
This commit is contained in:
parent
b238c41b26
commit
c28067d672
|
@ -6,8 +6,8 @@ from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
|
||||||
from lib.sata.link.scrambler import SATAScrambler
|
from lib.sata.link.scrambler import SATAScrambler
|
||||||
from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
|
from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
|
||||||
|
|
||||||
# TODO:
|
#TODO:
|
||||||
# - Do more tests
|
# -Test HOLD on RX path
|
||||||
|
|
||||||
from_rx = [
|
from_rx = [
|
||||||
("idle", 1),
|
("idle", 1),
|
||||||
|
@ -67,16 +67,19 @@ class SATALinkLayerTX(Module):
|
||||||
|
|
||||||
# FSM
|
# FSM
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
|
scrambler.reset.eq(1),
|
||||||
|
If(self.from_rx.idle,
|
||||||
insert.eq(primitives["SYNC"]),
|
insert.eq(primitives["SYNC"]),
|
||||||
If(scrambler.source.stb & scrambler.source.sop,
|
If(scrambler.source.stb & scrambler.source.sop,
|
||||||
If(self.from_rx.idle,
|
NextState("RDY"),
|
||||||
NextState("RDY")
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("RDY",
|
fsm.act("RDY",
|
||||||
insert.eq(primitives["X_RDY"]),
|
insert.eq(primitives["X_RDY"]),
|
||||||
If(self.from_rx.det == primitives["R_RDY"],
|
If(~self.from_rx.idle,
|
||||||
|
NextState("IDLE")
|
||||||
|
).Elif(self.from_rx.det == primitives["R_RDY"],
|
||||||
NextState("SOF")
|
NextState("SOF")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -141,12 +144,25 @@ class SATALinkLayerRX(Module):
|
||||||
crc = SATACRCChecker(link_layout(32))
|
crc = SATACRCChecker(link_layout(32))
|
||||||
self.submodules += crc
|
self.submodules += crc
|
||||||
|
|
||||||
|
sop = Signal()
|
||||||
|
self.sync += \
|
||||||
|
If(fsm.ongoing("RDY"),
|
||||||
|
sop.eq(1)
|
||||||
|
).Elif(scrambler.sink.stb & scrambler.sink.ack,
|
||||||
|
sop.eq(0)
|
||||||
|
)
|
||||||
|
|
||||||
# graph
|
# graph
|
||||||
self.comb += [
|
self.sync += \
|
||||||
If(fsm.ongoing("COPY") & (det == 0),
|
If(fsm.ongoing("COPY") & (det == 0),
|
||||||
scrambler.sink.stb.eq(cont.source.stb & (cont.source.charisk == 0)),
|
scrambler.sink.stb.eq(cont.source.stb & (cont.source.charisk == 0)),
|
||||||
scrambler.sink.d.eq(cont.source.data),
|
scrambler.sink.d.eq(cont.source.data),
|
||||||
),
|
).Else(
|
||||||
|
scrambler.sink.stb.eq(0)
|
||||||
|
)
|
||||||
|
self.comb += [
|
||||||
|
scrambler.sink.sop.eq(sop),
|
||||||
|
scrambler.sink.eop.eq(det == primitives["EOF"]),
|
||||||
cont.source.ack.eq(1),
|
cont.source.ack.eq(1),
|
||||||
Record.connect(scrambler.source, crc.sink),
|
Record.connect(scrambler.source, crc.sink),
|
||||||
Record.connect(crc.source, self.source)
|
Record.connect(crc.source, self.source)
|
||||||
|
@ -154,6 +170,7 @@ class SATALinkLayerRX(Module):
|
||||||
|
|
||||||
# FSM
|
# FSM
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
|
scrambler.reset.eq(1),
|
||||||
If(det == primitives["X_RDY"],
|
If(det == primitives["X_RDY"],
|
||||||
NextState("RDY")
|
NextState("RDY")
|
||||||
)
|
)
|
||||||
|
@ -165,6 +182,7 @@ class SATALinkLayerRX(Module):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("COPY",
|
fsm.act("COPY",
|
||||||
|
insert.eq(primitives["R_IP"]),
|
||||||
If(det == primitives["HOLD"],
|
If(det == primitives["HOLD"],
|
||||||
insert.eq(primitives["HOLDA"])
|
insert.eq(primitives["HOLDA"])
|
||||||
).Elif(det == primitives["EOF"],
|
).Elif(det == primitives["EOF"],
|
||||||
|
|
|
@ -48,7 +48,7 @@ class SATACONTInserter(Module):
|
||||||
)
|
)
|
||||||
|
|
||||||
# scrambler (between CONT and next primitive)
|
# scrambler (between CONT and next primitive)
|
||||||
scrambler = Scrambler()
|
scrambler = InsertReset(Scrambler())
|
||||||
self.submodules += scrambler
|
self.submodules += scrambler
|
||||||
self.comb += [
|
self.comb += [
|
||||||
scrambler.reset.eq(ResetSignal()), #XXX: should be reseted on COMINIT / COMRESET
|
scrambler.reset.eq(ResetSignal()), #XXX: should be reseted on COMINIT / COMRESET
|
||||||
|
|
|
@ -3,7 +3,6 @@ from migen.genlib.misc import optree
|
||||||
|
|
||||||
from lib.sata.std import *
|
from lib.sata.std import *
|
||||||
|
|
||||||
@DecorateModule(InsertReset)
|
|
||||||
@DecorateModule(InsertCE)
|
@DecorateModule(InsertCE)
|
||||||
class Scrambler(Module):
|
class Scrambler(Module):
|
||||||
"""SATA Scrambler
|
"""SATA Scrambler
|
||||||
|
@ -68,6 +67,7 @@ class Scrambler(Module):
|
||||||
|
|
||||||
self.comb += self.value.eq(next_value)
|
self.comb += self.value.eq(next_value)
|
||||||
|
|
||||||
|
@DecorateModule(InsertReset)
|
||||||
class SATAScrambler(Module):
|
class SATAScrambler(Module):
|
||||||
def __init__(self, layout):
|
def __init__(self, layout):
|
||||||
self.sink = sink = Sink(layout)
|
self.sink = sink = Sink(layout)
|
||||||
|
@ -76,18 +76,8 @@ class SATAScrambler(Module):
|
||||||
###
|
###
|
||||||
|
|
||||||
self.submodules.scrambler = Scrambler()
|
self.submodules.scrambler = Scrambler()
|
||||||
ongoing = Signal()
|
|
||||||
self.sync += \
|
|
||||||
If(sink.stb & sink.ack,
|
|
||||||
If(sink.eop,
|
|
||||||
ongoing.eq(0)
|
|
||||||
).Elif(sink.sop,
|
|
||||||
ongoing.eq(1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.scrambler.ce.eq(sink.stb & sink.ack & (sink.sop | ongoing)),
|
self.scrambler.ce.eq(sink.stb & sink.ack),
|
||||||
self.scrambler.reset.eq(~(sink.sop | ongoing)),
|
|
||||||
Record.connect(sink, source),
|
Record.connect(sink, source),
|
||||||
source.d.eq(sink.d ^ self.scrambler.value)
|
source.d.eq(sink.d ^ self.scrambler.value)
|
||||||
]
|
]
|
||||||
|
|
|
@ -49,7 +49,7 @@ class PHYSink(Module):
|
||||||
self.dword.dat = selfp.sink.data
|
self.dword.dat = selfp.sink.data
|
||||||
|
|
||||||
class PHYLayer(Module):
|
class PHYLayer(Module):
|
||||||
def __init__(self, debug):
|
def __init__(self, debug=False):
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
|
||||||
self.submodules.rx = PHYSink()
|
self.submodules.rx = PHYSink()
|
||||||
|
@ -116,8 +116,8 @@ class LinkRXPacket(LinkPacket):
|
||||||
|
|
||||||
class LinkTXPacket(LinkPacket):
|
class LinkTXPacket(LinkPacket):
|
||||||
def encode(self):
|
def encode(self):
|
||||||
self.scramble()
|
|
||||||
self.insert_crc()
|
self.insert_crc()
|
||||||
|
self.scramble()
|
||||||
|
|
||||||
def scramble(self):
|
def scramble(self):
|
||||||
for i in range(len(self)):
|
for i in range(len(self)):
|
||||||
|
@ -125,7 +125,7 @@ class LinkTXPacket(LinkPacket):
|
||||||
|
|
||||||
def insert_crc(self):
|
def insert_crc(self):
|
||||||
stdin = ""
|
stdin = ""
|
||||||
for v in self[:-1]:
|
for v in self:
|
||||||
stdin += "0x%08x " %v
|
stdin += "0x%08x " %v
|
||||||
stdin += "exit"
|
stdin += "exit"
|
||||||
with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
|
with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
|
||||||
|
@ -135,16 +135,20 @@ class LinkTXPacket(LinkPacket):
|
||||||
self.append(crc)
|
self.append(crc)
|
||||||
|
|
||||||
class LinkLayer(Module):
|
class LinkLayer(Module):
|
||||||
def __init__(self, phy, debug, hold_random_level=0):
|
def __init__(self, phy, debug=False, random_level=0):
|
||||||
self.phy = phy
|
self.phy = phy
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.hold_random_level = hold_random_level
|
self.random_level = random_level
|
||||||
|
self.tx_packets = []
|
||||||
self.tx_packet = LinkTXPacket()
|
self.tx_packet = LinkTXPacket()
|
||||||
self.rx_packet = LinkRXPacket()
|
self.rx_packet = LinkRXPacket()
|
||||||
self.rx_cont = False
|
self.rx_cont = False
|
||||||
|
|
||||||
self.transport_callback = None
|
self.transport_callback = None
|
||||||
|
|
||||||
|
self.send_state = ""
|
||||||
|
self.send_states = ["RDY", "SOF", "DATA", "EOF", "WTRM"]
|
||||||
|
|
||||||
def set_transport_callback(self, callback):
|
def set_transport_callback(self, callback):
|
||||||
self.transport_callback = callback
|
self.transport_callback = callback
|
||||||
|
|
||||||
|
@ -156,41 +160,67 @@ class LinkLayer(Module):
|
||||||
|
|
||||||
if dword == primitives["X_RDY"]:
|
if dword == primitives["X_RDY"]:
|
||||||
self.phy.send(primitives["R_RDY"])
|
self.phy.send(primitives["R_RDY"])
|
||||||
|
|
||||||
elif dword == primitives["WTRM"]:
|
elif dword == primitives["WTRM"]:
|
||||||
self.phy.send(primitives["R_OK"])
|
self.phy.send(primitives["R_OK"])
|
||||||
|
if self.rx_packet.ongoing:
|
||||||
elif dword == primitives["HOLD"]:
|
|
||||||
self.phy.send(primitives["HOLDA"])
|
|
||||||
|
|
||||||
elif dword == primitives["EOF"]:
|
|
||||||
self.rx_packet.decode()
|
self.rx_packet.decode()
|
||||||
if self.transport_callback is not None:
|
if self.transport_callback is not None:
|
||||||
self.transport_callback(self.rx_packet)
|
self.transport_callback(self.rx_packet)
|
||||||
self.rx_packet.ongoing = False
|
self.rx_packet.ongoing = False
|
||||||
|
elif dword == primitives["HOLD"]:
|
||||||
|
self.phy.send(primitives["HOLDA"])
|
||||||
|
elif dword == primitives["EOF"]:
|
||||||
|
pass
|
||||||
elif self.rx_packet.ongoing:
|
elif self.rx_packet.ongoing:
|
||||||
if dword != primitives["HOLD"]:
|
if dword != primitives["HOLD"]:
|
||||||
n = randn(100)
|
n = randn(100)
|
||||||
if n < self.hold_random_level:
|
if n < self.random_level:
|
||||||
self.phy.send(primitives["HOLD"])
|
self.phy.send(primitives["HOLD"])
|
||||||
else:
|
else:
|
||||||
self.phy.send(primitives["R_RDY"])
|
self.phy.send(primitives["R_IP"])
|
||||||
if not is_primitive(dword):
|
if not is_primitive(dword):
|
||||||
if not self.rx_cont:
|
if not self.rx_cont:
|
||||||
self.rx_packet.append(dword)
|
self.rx_packet.append(dword)
|
||||||
|
|
||||||
elif dword == primitives["SOF"]:
|
elif dword == primitives["SOF"]:
|
||||||
self.rx_packet = LinkRXPacket()
|
self.rx_packet = LinkRXPacket()
|
||||||
self.rx_packet.ongoing = True
|
self.rx_packet.ongoing = True
|
||||||
|
|
||||||
def send(self, packet):
|
def send(self, dword):
|
||||||
pass
|
if self.send_state == "RDY":
|
||||||
|
self.phy.send(primitives["X_RDY"])
|
||||||
|
if dword == primitives["R_RDY"]:
|
||||||
|
self.send_state = "SOF"
|
||||||
|
elif self.send_state == "SOF":
|
||||||
|
self.phy.send(primitives["SOF"])
|
||||||
|
self.send_state = "DATA"
|
||||||
|
elif self.send_state == "DATA":
|
||||||
|
self.phy.send(self.tx_packet.pop(0))
|
||||||
|
if len(self.tx_packet) == 0:
|
||||||
|
self.send_state = "EOF"
|
||||||
|
elif self.send_state == "EOF":
|
||||||
|
self.phy.send(primitives["EOF"])
|
||||||
|
self.send_state = "WTRM"
|
||||||
|
elif self.send_state == "WTRM":
|
||||||
|
self.phy.send(primitives["WTRM"])
|
||||||
|
if dword == primitives["R_OK"]:
|
||||||
|
self.tx_packet.done = True
|
||||||
|
elif dword == primitives["R_ERR"]:
|
||||||
|
self.tx_packet.done = True
|
||||||
|
|
||||||
def gen_simulation(self, selfp):
|
def gen_simulation(self, selfp):
|
||||||
self.phy.send(primitives["SYNC"])
|
self.tx_packet.done = True
|
||||||
while True:
|
while True:
|
||||||
yield from self.phy.receive()
|
yield from self.phy.receive()
|
||||||
|
self.phy.send(primitives["SYNC"])
|
||||||
|
rx_dword = self.phy.rx.dword.dat
|
||||||
|
if len(self.tx_packets) != 0:
|
||||||
|
if self.tx_packet.done:
|
||||||
|
self.tx_packet = self.tx_packets.pop(0)
|
||||||
|
self.tx_packet.encode()
|
||||||
|
self.send_state = "RDY"
|
||||||
|
if not self.tx_packet.done:
|
||||||
|
self.send(rx_dword)
|
||||||
|
else:
|
||||||
self.callback(self.phy.rx.dword.dat)
|
self.callback(self.phy.rx.dword.dat)
|
||||||
|
|
||||||
def get_field_data(field, packet):
|
def get_field_data(field, packet):
|
||||||
|
@ -282,8 +312,11 @@ class FIS_UNKNOWN(FIS):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
class TransportLayer(Module):
|
class TransportLayer(Module):
|
||||||
def __init__(self, link):
|
def __init__(self, link, debug=False, loopback=False):
|
||||||
pass
|
self.link = link
|
||||||
|
self.debug = debug
|
||||||
|
self.loopback = loopback
|
||||||
|
self.link.set_transport_callback(self.callback)
|
||||||
|
|
||||||
def callback(self, packet):
|
def callback(self, packet):
|
||||||
fis_type = packet[0]
|
fis_type = packet[0]
|
||||||
|
@ -301,12 +334,19 @@ class TransportLayer(Module):
|
||||||
fis = FIS_PIO_SETUP_D2H(packet)
|
fis = FIS_PIO_SETUP_D2H(packet)
|
||||||
else:
|
else:
|
||||||
fis = FIS_UNKNOWN(packet)
|
fis = FIS_UNKNOWN(packet)
|
||||||
|
if self.debug:
|
||||||
print(fis)
|
print(fis)
|
||||||
|
if self.loopback:
|
||||||
|
packet = LinkTXPacket(fis.packet)
|
||||||
|
self.link.tx_packets.append(packet)
|
||||||
|
|
||||||
class BFM(Module):
|
class BFM(Module):
|
||||||
def __init__(self, dw, debug=False, hold_random_level=0):
|
def __init__(self,
|
||||||
|
phy_debug=False,
|
||||||
|
link_debug=False, link_random_level=0,
|
||||||
|
transport_debug=False, transport_loopback=False
|
||||||
|
):
|
||||||
###
|
###
|
||||||
self.submodules.phy = PHYLayer(debug)
|
self.submodules.phy = PHYLayer(phy_debug)
|
||||||
self.submodules.link = LinkLayer(self.phy, debug, hold_random_level)
|
self.submodules.link = LinkLayer(self.phy, link_debug, link_random_level)
|
||||||
self.submodules.transport = TransportLayer(self.link)
|
self.submodules.transport = TransportLayer(self.link, transport_debug, transport_loopback)
|
||||||
self.link.set_transport_callback(self.transport.callback)
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ from lib.sata.test.bfm import *
|
||||||
from lib.sata.test.common import *
|
from lib.sata.test.common import *
|
||||||
|
|
||||||
class LinkStreamer(Module):
|
class LinkStreamer(Module):
|
||||||
def __init__(self, dw):
|
def __init__(self):
|
||||||
self.source = Source(link_layout(dw))
|
self.source = Source(link_layout(32))
|
||||||
###
|
###
|
||||||
self.packets = []
|
self.packets = []
|
||||||
self.packet = LinkTXPacket()
|
self.packet = LinkTXPacket()
|
||||||
|
@ -43,8 +43,8 @@ class LinkStreamer(Module):
|
||||||
selfp.source.stb = 0
|
selfp.source.stb = 0
|
||||||
|
|
||||||
class LinkLogger(Module):
|
class LinkLogger(Module):
|
||||||
def __init__(self, dw):
|
def __init__(self):
|
||||||
self.sink = Sink(link_layout(dw))
|
self.sink = Sink(link_layout(32))
|
||||||
###
|
###
|
||||||
self.packet = LinkRXPacket()
|
self.packet = LinkRXPacket()
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ class LinkLogger(Module):
|
||||||
selfp.sink.ack = 1
|
selfp.sink.ack = 1
|
||||||
if selfp.sink.stb == 1 and selfp.sink.sop == 1:
|
if selfp.sink.stb == 1 and selfp.sink.sop == 1:
|
||||||
self.packet = LinkRXPacket()
|
self.packet = LinkRXPacket()
|
||||||
|
print("rx : %08x" %selfp.sink.d)
|
||||||
self.packet.append(selfp.sink.d)
|
self.packet.append(selfp.sink.d)
|
||||||
elif selfp.sink.stb:
|
elif selfp.sink.stb:
|
||||||
self.packet.append(selfp.sink.d)
|
self.packet.append(selfp.sink.d)
|
||||||
|
@ -65,13 +66,14 @@ class LinkLogger(Module):
|
||||||
|
|
||||||
class TB(Module):
|
class TB(Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.submodules.bfm = BFM(32, debug=True, hold_random_level=50)
|
self.submodules.bfm = BFM(phy_debug=False,
|
||||||
|
link_random_level=50, transport_debug=False, transport_loopback=True)
|
||||||
self.submodules.link_layer = SATALinkLayer(self.bfm.phy)
|
self.submodules.link_layer = SATALinkLayer(self.bfm.phy)
|
||||||
|
|
||||||
self.submodules.streamer = LinkStreamer(32)
|
self.submodules.streamer = LinkStreamer()
|
||||||
streamer_ack_randomizer = AckRandomizer(link_layout(32), level=50)
|
streamer_ack_randomizer = AckRandomizer(link_layout(32), level=50)
|
||||||
self.submodules += streamer_ack_randomizer
|
self.submodules += streamer_ack_randomizer
|
||||||
self.submodules.logger = LinkLogger(32)
|
self.submodules.logger = LinkLogger()
|
||||||
self.comb += [
|
self.comb += [
|
||||||
Record.connect(self.streamer.source, streamer_ack_randomizer.sink),
|
Record.connect(self.streamer.source, streamer_ack_randomizer.sink),
|
||||||
Record.connect(streamer_ack_randomizer.source, self.link_layer.sink),
|
Record.connect(streamer_ack_randomizer.source, self.link_layer.sink),
|
||||||
|
@ -79,10 +81,16 @@ class TB(Module):
|
||||||
]
|
]
|
||||||
|
|
||||||
def gen_simulation(self, selfp):
|
def gen_simulation(self, selfp):
|
||||||
for i in range(200):
|
for i in range(24):
|
||||||
yield
|
yield
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
yield from self.streamer.send(LinkTXPacket([i for i in range(16)]))
|
yield from self.streamer.send(LinkTXPacket([i for i in range(16)]))
|
||||||
|
yield from self.logger.receive()
|
||||||
|
print("Logger:")
|
||||||
|
print("-------")
|
||||||
|
for v in self.logger.packet:
|
||||||
|
print("%08x" %v)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run_simulation(TB(), ncycles=512, vcd_name="my.vcd", keep_files=True)
|
run_simulation(TB(), ncycles=512, vcd_name="my.vcd", keep_files=True)
|
||||||
|
|
Loading…
Reference in New Issue