From: Florent Kermarrec Date: Tue, 11 Nov 2014 17:47:34 +0000 (+0100) Subject: link: prepare simulation X-Git-Tag: 24jan2021_ls180~2572^2~163 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b423c1df4b66e42c519ca862cfa5f0f7afac25c8;p=litex.git link: prepare simulation --- diff --git a/lib/sata/link/__init__.py b/lib/sata/link/__init__.py index 65eb8cab..4d072709 100644 --- a/lib/sata/link/__init__.py +++ b/lib/sata/link/__init__.py @@ -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") ) ) diff --git a/lib/sata/link/crc.py b/lib/sata/link/crc.py index e7bb3bb0..2f3aa367 100644 --- a/lib/sata/link/crc.py +++ b/lib/sata/link/crc.py @@ -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() diff --git a/lib/sata/link/scrambler.py b/lib/sata/link/scrambler.py index 8f301a19..df599fec 100644 --- a/lib/sata/link/scrambler.py +++ b/lib/sata/link/scrambler.py @@ -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) ) ) diff --git a/lib/sata/link/test/Makefile b/lib/sata/link/test/Makefile index bd6ef493..4f621c37 100644 --- a/lib/sata/link/test/Makefile +++ b/lib/sata/link/test/Makefile @@ -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: diff --git a/lib/sata/link/test/bfm.py b/lib/sata/link/test/bfm.py new file mode 100644 index 00000000..10c87e42 --- /dev/null +++ b/lib/sata/link/test/bfm.py @@ -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)) diff --git a/lib/sata/link/test/link_tb.py b/lib/sata/link/test/link_tb.py new file mode 100644 index 00000000..7753e5b0 --- /dev/null +++ b/lib/sata/link/test/link_tb.py @@ -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) diff --git a/lib/sata/std.py b/lib/sata/std.py index a6d4c028..191778fc 100644 --- a/lib/sata/std.py +++ b/lib/sata/std.py @@ -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 }