link: prepare simulation
This commit is contained in:
parent
64ed34b35a
commit
b423c1df4b
|
@ -1,34 +1,35 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
|
from migen.genlib.fsm import FSM, NextState
|
||||||
|
|
||||||
from lib.sata.std import *
|
from lib.sata.std import *
|
||||||
from lib.sata.link import crc
|
from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
|
||||||
from lib.sata.link import scrambler
|
from lib.sata.link.scrambler import SATAScrambler
|
||||||
|
|
||||||
# Todo:
|
# Todo:
|
||||||
# - TX: (optional) insert COND and scramble between COND and primitives
|
# - TX: (optional) insert COND and scramble between COND and primitives
|
||||||
# - RX: manage COND, HOLD from device
|
# - RX: manage COND, HOLD from device
|
||||||
|
|
||||||
class SATALinkLayer(Module):
|
class SATALinkLayer(Module):
|
||||||
def __init__(self, phy, dw=32):
|
def __init__(self, phy):
|
||||||
self.sink = Sink(link_layout(dw))
|
self.sink = Sink(link_layout(32))
|
||||||
self.source = Source(link_layout(dw))
|
self.source = Source(link_layout(32))
|
||||||
|
|
||||||
fsm = FSM(reset_state="IDLE")
|
fsm = FSM(reset_state="IDLE")
|
||||||
self.submodules += fsm
|
self.submodules += fsm
|
||||||
|
|
||||||
# TX
|
# TX
|
||||||
# insert CRC
|
# insert CRC
|
||||||
crc_inserter = crc.SATACRCInserter(link_layout(dw))
|
crc_inserter = SATACRCInserter(link_layout(32))
|
||||||
self.submodules += crc_inserter
|
self.submodules += crc_inserter
|
||||||
|
|
||||||
# scramble
|
# scramble
|
||||||
scrambler = scrambler.SATAScrambler(link_layout(dw))
|
scrambler = SATAScrambler(link_layout(32))
|
||||||
self.submodules += scrambler
|
self.submodules += scrambler
|
||||||
|
|
||||||
# graph
|
# graph
|
||||||
self.comb += [
|
self.comb += [
|
||||||
Record.connect(self.sink, crc_inserter.sink),
|
Record.connect(self.sink, crc_inserter.sink),
|
||||||
Record.connect(crc_inserter, scrambler)
|
Record.connect(crc_inserter.source, scrambler.sink)
|
||||||
]
|
]
|
||||||
|
|
||||||
# datas / primitives mux
|
# datas / primitives mux
|
||||||
|
@ -38,9 +39,9 @@ class SATALinkLayer(Module):
|
||||||
phy.sink.stb.eq(1),
|
phy.sink.stb.eq(1),
|
||||||
phy.sink.data.eq(tx_insert),
|
phy.sink.data.eq(tx_insert),
|
||||||
phy.sink.charisk.eq(0x0001),
|
phy.sink.charisk.eq(0x0001),
|
||||||
).Elsif(fsm.ongoing("H2D_COPY"),
|
).Elif(fsm.ongoing("H2D_COPY"),
|
||||||
phy.sink.stb.eq(scrambler.source.stb),
|
phy.sink.stb.eq(scrambler.source.stb),
|
||||||
phy.sink.data.eq(scrambler.source.data),
|
phy.sink.data.eq(scrambler.source.d),
|
||||||
scrambler.source.ack.eq(phy.source.ack),
|
scrambler.source.ack.eq(phy.source.ack),
|
||||||
phy.sink.charisk.eq(0)
|
phy.sink.charisk.eq(0)
|
||||||
)
|
)
|
||||||
|
@ -55,19 +56,20 @@ class SATALinkLayer(Module):
|
||||||
)
|
)
|
||||||
|
|
||||||
# descrambler
|
# descrambler
|
||||||
descrambler = descrambler.SATAScrambler(link_layout(dw))
|
descrambler = SATAScrambler(link_layout(32))
|
||||||
self.submodules += descrambler
|
self.submodules += descrambler
|
||||||
|
|
||||||
# check CRC
|
# check CRC
|
||||||
crc_checker = crc.SATACRCChecker(link_layout(dw))
|
crc_checker = SATACRCChecker(link_layout(32))
|
||||||
self.submodules += crc_checker
|
self.submodules += crc_checker
|
||||||
|
|
||||||
# graph
|
# graph
|
||||||
self.comb += [
|
self.comb += [
|
||||||
If(fsm.ongoing("H2D_COPY") & (rx_det == 0),
|
If(fsm.ongoing("H2D_COPY") & (rx_det == 0),
|
||||||
descrambler.sink.stb.eq(phy.source.stb & (phy.charisk == 0)),
|
descrambler.sink.stb.eq(phy.source.stb & (phy.source.charisk == 0)),
|
||||||
descrambler.sink.d.eq(phy.source.d),
|
descrambler.sink.d.eq(phy.source.data),
|
||||||
),
|
),
|
||||||
|
phy.source.ack.eq(1),
|
||||||
Record.connect(descrambler.source, crc_checker.sink),
|
Record.connect(descrambler.source, crc_checker.sink),
|
||||||
Record.connect(crc_checker.source, self.source)
|
Record.connect(crc_checker.source, self.source)
|
||||||
]
|
]
|
||||||
|
@ -75,9 +77,9 @@ class SATALinkLayer(Module):
|
||||||
# FSM
|
# FSM
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
tx_insert.eq(primitives["SYNC"]),
|
tx_insert.eq(primitives["SYNC"]),
|
||||||
If(rx_primitive == "X_RDY",
|
If(rx_det == primitives["X_RDY"],
|
||||||
NextState("D2H_RDY")
|
NextState("D2H_RDY")
|
||||||
).Elif(scrambler.stb & scrambler.sop,
|
).Elif(scrambler.source.stb & scrambler.source.sop,
|
||||||
NextState("H2D_RDY")
|
NextState("H2D_RDY")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -85,8 +87,9 @@ class SATALinkLayer(Module):
|
||||||
# Host to Device
|
# Host to Device
|
||||||
fsm.act("H2D_RDY",
|
fsm.act("H2D_RDY",
|
||||||
tx_insert.eq(primitives["X_RDY"]),
|
tx_insert.eq(primitives["X_RDY"]),
|
||||||
If(rx_primitive == primitives["R_RDY"]),
|
If(rx_det == primitives["R_RDY"],
|
||||||
NextState("H2D_SOF")
|
NextState("H2D_SOF")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
fsm.act("H2D_SOF",
|
fsm.act("H2D_SOF",
|
||||||
tx_insert.eq(primitives["SOF"]),
|
tx_insert.eq(primitives["SOF"]),
|
||||||
|
@ -95,7 +98,7 @@ class SATALinkLayer(Module):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("H2D_COPY",
|
fsm.act("H2D_COPY",
|
||||||
If(scrambler.stb & scrambler.ack & scramvbler.eop,
|
If(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
|
||||||
NextState("H2D_EOF")
|
NextState("H2D_EOF")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -90,7 +90,7 @@ class SATACRC(Module):
|
||||||
polynom = 0x04C11DB7
|
polynom = 0x04C11DB7
|
||||||
init = 0x52325032
|
init = 0x52325032
|
||||||
check = 0xC704DD7B
|
check = 0xC704DD7B
|
||||||
def __init__(self):
|
def __init__(self, dat_width):
|
||||||
self.d = Signal(self.width)
|
self.d = Signal(self.width)
|
||||||
self.value = Signal(self.width)
|
self.value = Signal(self.width)
|
||||||
self.error = Signal()
|
self.error = Signal()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
from migen.genlib.misc import optree
|
from migen.genlib.misc import optree
|
||||||
|
|
||||||
|
from lib.sata.std import *
|
||||||
|
|
||||||
@DecorateModule(InsertReset)
|
@DecorateModule(InsertReset)
|
||||||
@DecorateModule(InsertCE)
|
@DecorateModule(InsertCE)
|
||||||
class Scrambler(Module):
|
class Scrambler(Module):
|
||||||
|
@ -79,7 +81,7 @@ class SATAScrambler(Module):
|
||||||
If(sink.stb & sink.ack,
|
If(sink.stb & sink.ack,
|
||||||
If(sink.eop,
|
If(sink.eop,
|
||||||
ongoing.eq(0)
|
ongoing.eq(0)
|
||||||
).Elsif(sink.sop,
|
).Elif(sink.sop,
|
||||||
ongoing.eq(1)
|
ongoing.eq(1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,6 +14,9 @@ scrambler_tb:
|
||||||
$(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
|
$(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
|
||||||
$(CMD) scrambler_tb.py
|
$(CMD) scrambler_tb.py
|
||||||
|
|
||||||
|
link_tb:
|
||||||
|
$(CMD) link_tb.py
|
||||||
|
|
||||||
all: crc_tb scrambler_tb
|
all: crc_tb scrambler_tb
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
|
||||||
|
from lib.sata.std import *
|
||||||
|
|
||||||
|
class BFMDword():
|
||||||
|
def __init__(self, dat=0):
|
||||||
|
self.dat = dat
|
||||||
|
self.start = 1
|
||||||
|
self.done = 0
|
||||||
|
|
||||||
|
class BFMSource(Module):
|
||||||
|
def __init__(self, dw):
|
||||||
|
self.source = Source(phy_layout(dw))
|
||||||
|
###
|
||||||
|
self.dwords = []
|
||||||
|
self.dword = BFMDword()
|
||||||
|
self.dword.done = 1
|
||||||
|
|
||||||
|
def send(self, dword, blocking=True):
|
||||||
|
self.dwords.append(dword)
|
||||||
|
if blocking:
|
||||||
|
while dword.done == 0:
|
||||||
|
yield
|
||||||
|
|
||||||
|
def do_simulation(self, selfp):
|
||||||
|
if len(self.dwords) and self.dword.done:
|
||||||
|
self.dword = self.dwords.pop(0)
|
||||||
|
if not self.dword.done:
|
||||||
|
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
|
||||||
|
elif selfp.source.stb == 1 and selfp.source.ack == 1:
|
||||||
|
self.dword.done = 1
|
||||||
|
selfp.source.stb = 0
|
||||||
|
|
||||||
|
class BFMSink(Module):
|
||||||
|
def __init__(self, dw):
|
||||||
|
self.sink = Sink(phy_layout(dw))
|
||||||
|
###
|
||||||
|
self.dword = BFMDword()
|
||||||
|
|
||||||
|
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 BFMPHY(Module):
|
||||||
|
def __init__(self, dw):
|
||||||
|
self.dw = dw
|
||||||
|
|
||||||
|
self.submodules.bfm_sink = BFMSink(dw)
|
||||||
|
self.submodules.bfm_source = BFMSource(dw)
|
||||||
|
|
||||||
|
self.source = self.bfm_source.source
|
||||||
|
self.sink = self.bfm_sink.sink
|
||||||
|
|
||||||
|
self.dword = 0
|
||||||
|
|
||||||
|
def send(self, dword, blocking=True):
|
||||||
|
packet = BFMDword(dword)
|
||||||
|
yield from self.bfm_source.send(dword, blocking)
|
||||||
|
|
||||||
|
def receive(self):
|
||||||
|
yield from self.bfm_sink.receive()
|
||||||
|
self.rx_dword = self.bfm_sink.dword.dat
|
||||||
|
|
||||||
|
class BFM(Module):
|
||||||
|
def __init__(self, dw, debug=False):
|
||||||
|
self.debug = debug
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
self.submodules.phy = BFMPHY(dw)
|
||||||
|
|
||||||
|
def gen_simulation(self, selfp):
|
||||||
|
while True:
|
||||||
|
yield from self.phy.receive()
|
||||||
|
print("%08x" %(self.phy.rx_dword))
|
|
@ -0,0 +1,90 @@
|
||||||
|
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 *
|
||||||
|
|
||||||
|
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)
|
||||||
|
self.submodules.link_layer = SATALinkLayer(self.bfm.phy)
|
||||||
|
|
||||||
|
self.submodules.streamer = LinkStreamer(32)
|
||||||
|
self.submodules.logger = LinkLogger(32)
|
||||||
|
self.comb += [
|
||||||
|
self.link_layer.sink.eq(self.streamer.source),
|
||||||
|
self.logger.sink.eq(self.link_layer.source)
|
||||||
|
]
|
||||||
|
|
||||||
|
def gen_simulation(self, selfp):
|
||||||
|
for i in range(200):
|
||||||
|
yield
|
||||||
|
yield from self.bfm.phy.send(BFMDword(primitives["R_RDY"]), False)
|
||||||
|
yield from self.streamer.send(LinkPacket([0, 1, 2, 3]))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run_simulation(TB(), ncycles=5000, vcd_name="my.vcd", keep_files=True)
|
|
@ -1,6 +1,6 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
from migen.genlib.record import *
|
from migen.genlib.record import *
|
||||||
from migen.flow.actor import EndpointDescription
|
from migen.flow.actor import EndpointDescription, Sink, Source
|
||||||
|
|
||||||
primitives = {
|
primitives = {
|
||||||
"ALIGN" : 0x7B4A4ABC,
|
"ALIGN" : 0x7B4A4ABC,
|
||||||
|
@ -21,7 +21,7 @@ primitives = {
|
||||||
def ones(width):
|
def ones(width):
|
||||||
return 2**width-1
|
return 2**width-1
|
||||||
|
|
||||||
def phy_description(dw):
|
def phy_layout(dw):
|
||||||
parameters = {
|
parameters = {
|
||||||
"packetized": False
|
"packetized": False
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ def phy_description(dw):
|
||||||
]
|
]
|
||||||
return EndpointDescription(layout, parameters)
|
return EndpointDescription(layout, parameters)
|
||||||
|
|
||||||
def link_description(dw):
|
def link_layout(dw):
|
||||||
parameters = {
|
parameters = {
|
||||||
"packetized": True
|
"packetized": True
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue