link: prepare simulation

This commit is contained in:
Florent Kermarrec 2014-11-11 18:47:34 +01:00
parent 64ed34b35a
commit b423c1df4b
7 changed files with 209 additions and 23 deletions

View File

@ -1,34 +1,35 @@
from migen.fhdl.std import *
from migen.genlib.fsm import FSM, NextState
from lib.sata.std import *
from lib.sata.link import crc
from lib.sata.link import scrambler
from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
from lib.sata.link.scrambler import SATAScrambler
# Todo:
# - TX: (optional) insert COND and scramble between COND and primitives
# - RX: manage COND, HOLD from device
class SATALinkLayer(Module):
def __init__(self, phy, dw=32):
self.sink = Sink(link_layout(dw))
self.source = Source(link_layout(dw))
def __init__(self, phy):
self.sink = Sink(link_layout(32))
self.source = Source(link_layout(32))
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
# TX
# insert CRC
crc_inserter = crc.SATACRCInserter(link_layout(dw))
crc_inserter = SATACRCInserter(link_layout(32))
self.submodules += crc_inserter
# scramble
scrambler = scrambler.SATAScrambler(link_layout(dw))
scrambler = SATAScrambler(link_layout(32))
self.submodules += scrambler
# graph
self.comb += [
Record.connect(self.sink, crc_inserter.sink),
Record.connect(crc_inserter, scrambler)
Record.connect(crc_inserter.source, scrambler.sink)
]
# datas / primitives mux
@ -38,9 +39,9 @@ class SATALinkLayer(Module):
phy.sink.stb.eq(1),
phy.sink.data.eq(tx_insert),
phy.sink.charisk.eq(0x0001),
).Elsif(fsm.ongoing("H2D_COPY"),
).Elif(fsm.ongoing("H2D_COPY"),
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),
phy.sink.charisk.eq(0)
)
@ -55,19 +56,20 @@ class SATALinkLayer(Module):
)
# descrambler
descrambler = descrambler.SATAScrambler(link_layout(dw))
descrambler = SATAScrambler(link_layout(32))
self.submodules += descrambler
# check CRC
crc_checker = crc.SATACRCChecker(link_layout(dw))
crc_checker = SATACRCChecker(link_layout(32))
self.submodules += crc_checker
# graph
self.comb += [
If(fsm.ongoing("H2D_COPY") & (rx_det == 0),
descrambler.sink.stb.eq(phy.source.stb & (phy.charisk == 0)),
descrambler.sink.d.eq(phy.source.d),
descrambler.sink.stb.eq(phy.source.stb & (phy.source.charisk == 0)),
descrambler.sink.d.eq(phy.source.data),
),
phy.source.ack.eq(1),
Record.connect(descrambler.source, crc_checker.sink),
Record.connect(crc_checker.source, self.source)
]
@ -75,9 +77,9 @@ class SATALinkLayer(Module):
# FSM
fsm.act("IDLE",
tx_insert.eq(primitives["SYNC"]),
If(rx_primitive == "X_RDY",
If(rx_det == primitives["X_RDY"],
NextState("D2H_RDY")
).Elif(scrambler.stb & scrambler.sop,
).Elif(scrambler.source.stb & scrambler.source.sop,
NextState("H2D_RDY")
)
)
@ -85,8 +87,9 @@ class SATALinkLayer(Module):
# Host to Device
fsm.act("H2D_RDY",
tx_insert.eq(primitives["X_RDY"]),
If(rx_primitive == primitives["R_RDY"]),
If(rx_det == primitives["R_RDY"],
NextState("H2D_SOF")
)
)
fsm.act("H2D_SOF",
tx_insert.eq(primitives["SOF"]),
@ -95,7 +98,7 @@ class SATALinkLayer(Module):
)
)
fsm.act("H2D_COPY",
If(scrambler.stb & scrambler.ack & scramvbler.eop,
If(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
NextState("H2D_EOF")
)
)

View File

@ -90,7 +90,7 @@ class SATACRC(Module):
polynom = 0x04C11DB7
init = 0x52325032
check = 0xC704DD7B
def __init__(self):
def __init__(self, dat_width):
self.d = Signal(self.width)
self.value = Signal(self.width)
self.error = Signal()

View File

@ -1,6 +1,8 @@
from migen.fhdl.std import *
from migen.genlib.misc import optree
from lib.sata.std import *
@DecorateModule(InsertReset)
@DecorateModule(InsertCE)
class Scrambler(Module):
@ -79,7 +81,7 @@ class SATAScrambler(Module):
If(sink.stb & sink.ack,
If(sink.eop,
ongoing.eq(0)
).Elsif(sink.sop,
).Elif(sink.sop,
ongoing.eq(1)
)
)

View File

@ -14,6 +14,9 @@ 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:

88
lib/sata/link/test/bfm.py Normal file
View File

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

View File

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

View File

@ -1,6 +1,6 @@
from migen.fhdl.std import *
from migen.genlib.record import *
from migen.flow.actor import EndpointDescription
from migen.flow.actor import EndpointDescription, Sink, Source
primitives = {
"ALIGN" : 0x7B4A4ABC,
@ -21,7 +21,7 @@ primitives = {
def ones(width):
return 2**width-1
def phy_description(dw):
def phy_layout(dw):
parameters = {
"packetized": False
}
@ -31,7 +31,7 @@ def phy_description(dw):
]
return EndpointDescription(layout, parameters)
def link_description(dw):
def link_layout(dw):
parameters = {
"packetized": True
}