link: test RX path

This commit is contained in:
Florent Kermarrec 2014-12-05 20:26:09 +01:00
parent b238c41b26
commit c28067d672
5 changed files with 114 additions and 58 deletions

View File

@ -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"],

View File

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

View File

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

View File

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

View File

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