From 603b4cdc8cb3cbbfe1abc2e24a0d4e6e58c421f8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 1 May 2015 16:11:15 +0200 Subject: [PATCH] liteusb: continue refactoring (virtual UART and DMA working on minispartan6) - rename ft2232h phy to ft245. - make crc optional - fix depacketizer - refactor uart (it's now only a wrapper around standard UART) - fix and update dma --- misoclib/com/liteusb/common.py | 8 +- misoclib/com/liteusb/core/__init__.py | 40 +++---- misoclib/com/liteusb/core/crossbar.py | 2 +- misoclib/com/liteusb/core/packet.py | 6 +- misoclib/com/liteusb/frontend/dma.py | 19 ++-- misoclib/com/liteusb/frontend/uart.py | 66 ++++-------- .../com/liteusb/phy/{ft2232h.py => ft245.py} | 102 +++++++++--------- misoclib/com/liteusb/test/Makefile | 8 +- ...{ft2232h_async_tb.py => ft245_async_tb.py} | 41 ++++--- .../{ft2232h_sync_tb.py => ft245_sync_tb.py} | 8 +- 10 files changed, 141 insertions(+), 159 deletions(-) rename misoclib/com/liteusb/phy/{ft2232h.py => ft245.py} (82%) rename misoclib/com/liteusb/test/{ft2232h_async_tb.py => ft245_async_tb.py} (79%) rename misoclib/com/liteusb/test/{ft2232h_sync_tb.py => ft245_sync_tb.py} (94%) diff --git a/misoclib/com/liteusb/common.py b/misoclib/com/liteusb/common.py index df3d74829..2cbf00e62 100644 --- a/misoclib/com/liteusb/common.py +++ b/misoclib/com/liteusb/common.py @@ -3,6 +3,7 @@ from migen.genlib.fsm import * from migen.actorlib.fifo import * from migen.flow.actor import EndpointDescription from migen.actorlib.packet import * +from migen.actorlib.structuring import Pipeline packet_header_length = 9 @@ -49,11 +50,12 @@ class LiteUSBMasterPort: class LiteUSBSlavePort: - def __init__(self, dw): + def __init__(self, dw, tag): self.sink = Sink(user_description(dw)) self.source = Source(user_description(dw)) + self.tag = tag class LiteUSBUserPort(LiteUSBSlavePort): - def __init__(self, dw): - LiteUSBSlavePort.__init__(self, dw) + def __init__(self, dw, tag): + LiteUSBSlavePort.__init__(self, dw, tag) diff --git a/misoclib/com/liteusb/core/__init__.py b/misoclib/com/liteusb/core/__init__.py index b416a983b..9ecd835cb 100644 --- a/misoclib/com/liteusb/core/__init__.py +++ b/misoclib/com/liteusb/core/__init__.py @@ -3,29 +3,29 @@ from misoclib.com.liteusb.core.packet import LiteUSBPacketizer, LiteUSBDepacketi from misoclib.com.liteusb.core.crc import LiteUSBCRC32Inserter, LiteUSBCRC32Checker from misoclib.com.liteusb.core.crossbar import LiteUSBCrossbar -# XXX Header should be protected by CRC - class LiteUSBCore(Module): - def __init__(self, phy): + def __init__(self, phy, clk_freq, with_crc=True): + rx_pipeline = [phy] + tx_pipeline = [phy] + # depacketizer / packetizer - self.submodules.depacketizer = LiteUSBDepacketizer() + self.submodules.depacketizer = LiteUSBDepacketizer(clk_freq) self.submodules.packetizer = LiteUSBPacketizer() - self.comb += [ - Record.connect(phy.source, self.depacketizer.sink), - Record.connect(self.packetizer.source, phy.sink) - ] + rx_pipeline += [self.depacketizer] + tx_pipeline += [self.packetizer] - # crc checker / inserter - self.submodules.crc_rx = LiteUSBCRC32Checker() - self.submodules.crc_tx = LiteUSBCRC32Inserter() - self.comb += [ - Record.connect(self.depacketizer.source, self.crc_rx.sink), - Record.connect(self.crc_tx.source, self.packetizer.sink) - ] + if with_crc: + # crc checker / inserter + self.submodules.crc_rx = LiteUSBCRC32Checker() + self.submodules.crc_tx = LiteUSBCRC32Inserter() + rx_pipeline += [self.crc_rx] + tx_pipeline += [self.crc_tx] - # crossbar + # crossbar self.submodules.crossbar = LiteUSBCrossbar() - self.comb += [ - Record.connect(self.crossbar.master.source, self.crc_tx.sink), - Record.connect(self.crc_rx.source, self.crossbar.master.sink) - ] + rx_pipeline += [self.crossbar.master] + tx_pipeline += [self.crossbar.master] + + # graph + self.submodules.rx_pipeline = Pipeline(*rx_pipeline) + self.submodules.tx_pipeline = Pipeline(*reversed(tx_pipeline)) diff --git a/misoclib/com/liteusb/core/crossbar.py b/misoclib/com/liteusb/core/crossbar.py index e342712eb..59440df5b 100644 --- a/misoclib/com/liteusb/core/crossbar.py +++ b/misoclib/com/liteusb/core/crossbar.py @@ -9,7 +9,7 @@ class LiteUSBCrossbar(Module): self.dispatch_param = "dst" def get_port(self, dst): - port = LiteUSBUserPort(8) + port = LiteUSBUserPort(8, dst) if dst in self.users.keys(): raise ValueError("Destination {0:#x} already assigned".format(dst)) self.users[dst] = port diff --git a/misoclib/com/liteusb/core/packet.py b/misoclib/com/liteusb/core/packet.py index bb4c28ad4..43c97b014 100644 --- a/misoclib/com/liteusb/core/packet.py +++ b/misoclib/com/liteusb/core/packet.py @@ -66,7 +66,7 @@ class LiteUSBPacketizer(Module): class LiteUSBDepacketizer(Module): - def __init__(self, timeout=10): + def __init__(self, clk_freq, timeout=10): self.sink = sink = Sink(phy_description(8)) self.source = source = Source(user_description(8)) @@ -116,9 +116,9 @@ class LiteUSBDepacketizer(Module): header_pack.source.ack.eq(1), ) - self.submodules.timeout = Timeout(60000000*timeout) #XXX use clk_freq + self.submodules.timeout = Timeout(clk_freq*timeout) self.comb += [ - self.timeout.reset.eq(fsm.ongoing("WAIT_SOP")), + self.timeout.reset.eq(fsm.ongoing("IDLE")), self.timeout.ce.eq(1) ] diff --git a/misoclib/com/liteusb/frontend/dma.py b/misoclib/com/liteusb/frontend/dma.py index a9a967012..79f7ab67f 100644 --- a/misoclib/com/liteusb/frontend/dma.py +++ b/misoclib/com/liteusb/frontend/dma.py @@ -16,7 +16,7 @@ class LiteUSBDMAWriter(Module, AutoCSR): # Pack data pack_factor = lasmim.dw//8 - pack = structuring.Pack(phy_layout, pack_factor, reverse=True) + pack = structuring.Pack(phy_description(8), pack_factor, reverse=True) cast = structuring.Cast(pack.source.payload.layout, lasmim.dw) # DMA @@ -61,12 +61,12 @@ class LiteUSBDMAReader(Module, AutoCSR): pack_factor = lasmim.dw//8 packed_dat = structuring.pack_layout(8, pack_factor) cast = structuring.Cast(lasmim.dw, packed_dat) - unpack = structuring.Unpack(pack_factor, phy_layout, reverse=True) + unpack = structuring.Unpack(pack_factor, phy_description(8), reverse=True) # Graph cnt = Signal(32) self.sync += \ - If(self.dma.generator._r_shoot.re, + If(self.dma.generator._shoot.re, cnt.eq(0) ).Elif(source.stb & source.ack, cnt.eq(cnt + 1) @@ -92,12 +92,11 @@ class LiteUSBDMAReader(Module, AutoCSR): class LiteUSBDMA(Module, AutoCSR): - def __init__(self, lasmim_dma_wr, lasmim_dma_rd, tag): - self.tag = tag - + def __init__(self, port, lasmim_dma_wr, lasmim_dma_rd): self.submodules.writer = LiteUSBDMAWriter(lasmim_dma_wr) - self.submodules.reader = LiteUSBDMAReader(lasmim_dma_rd, self.tag) + self.submodules.reader = LiteUSBDMAReader(lasmim_dma_rd, port.tag) self.submodules.ev = SharedIRQ(self.writer.ev, self.reader.ev) - - self.sink = self.writer.sink - self.source = self.reader.source + self.comb += [ + Record.connect(port.source, self.writer.sink), + Record.connect(self.reader.source, port.sink), + ] diff --git a/misoclib/com/liteusb/frontend/uart.py b/misoclib/com/liteusb/frontend/uart.py index 6e551f00e..648d67639 100644 --- a/misoclib/com/liteusb/frontend/uart.py +++ b/misoclib/com/liteusb/frontend/uart.py @@ -1,59 +1,35 @@ from migen.fhdl.std import * -from migen.bank.description import * -from migen.bank.eventmanager import * -from migen.actorlib.fifo import SyncFIFO from misoclib.com.liteusb.common import * +from misoclib.com.uart import UART +class LiteUSBUARTPHY: + def __init__(self): + self.sink = Sink([("data", 8)]) + self.source = Source([("data", 8)]) -class LiteUSBUART(Module, AutoCSR): - def __init__(self, tag, fifo_depth=64): - self.tag = tag +class LiteUSBUART(UART): + def __init__(self, port, + tx_fifo_depth=16, + rx_fifo_depth=16): - self._rxtx = CSR(8) - - self.submodules.ev = EventManager() - self.ev.tx = EventSourcePulse() - self.ev.rx = EventSourceLevel() - self.ev.finalize() - - self.source = source = Source(user_description(8)) - self.sink = sink = Sink(user_description(8)) - - # # # + phy = LiteUSBUARTPHY() + UART.__init__(self, phy, tx_fifo_depth, rx_fifo_depth) # TX - tx_start = self._rxtx.re - tx_done = self.ev.tx.trigger - - self.sync += \ - If(tx_start, - source.stb.eq(1), - source.data.eq(self._rxtx.r), - ).Elif(tx_done, - source.stb.eq(0) - ) - self.comb += [ - source.sop.eq(1), - source.eop.eq(1), - source.length.eq(1), - source.dst.eq(self.tag), - tx_done.eq(source.stb & source.ack), + port.sink.stb.eq(phy.sink.stb), + port.sink.sop.eq(1), + port.sink.eop.eq(1), + port.sink.length.eq(1), + port.sink.dst.eq(port.tag), + port.sink.data.eq(phy.sink.data), + phy.sink.ack.eq(port.sink.ack) ] # RX - rx_available = self.ev.rx.trigger - - rx_fifo = SyncFIFO(8, fifo_depth) - self.submodules += rx_fifo self.comb += [ - Record.connect(sink, rx_fifo.sink), - - rx_fifo.we.eq(sink.stb), - sink.ack.eq(sink.stb & rx_fifo.writable), - rx_fifo.din.eq(sink.data), - rx_available.eq(rx_fifo.stb), - rx_fifo.ack.eq(self.ev.rx.clear), - self._rxtx.w.eq(rx_fifo.dout) + phy.source.stb.eq(port.source.stb), + phy.source.data.eq(port.source.data), + port.source.ack.eq(phy.source.ack) ] diff --git a/misoclib/com/liteusb/phy/ft2232h.py b/misoclib/com/liteusb/phy/ft245.py similarity index 82% rename from misoclib/com/liteusb/phy/ft2232h.py rename to misoclib/com/liteusb/phy/ft245.py index 92b4219ba..bed5f5d63 100644 --- a/misoclib/com/liteusb/phy/ft2232h.py +++ b/misoclib/com/liteusb/phy/ft245.py @@ -1,3 +1,5 @@ +import math + from migen.fhdl.std import * from migen.flow.actor import * from migen.actorlib.fifo import SyncFIFO, AsyncFIFO @@ -24,39 +26,31 @@ def anti_starvation(module, timeout): return en, max_time -class FT2232HPHYSynchronous(Module): - def __init__(self, pads, +class FT245PHYSynchronous(Module): + def __init__(self, pads, clk_freq, fifo_depth=32, - read_time=16, - write_time=16): + read_time=128, + write_time=128): dw = flen(pads.data) - # - # Read / Write Fifos - # - - # Read Fifo (Ftdi --> SoC) + # read fifo (FTDI --> SoC) read_fifo = RenameClockDomains(AsyncFIFO(phy_description(8), fifo_depth), {"write": "ftdi", "read": "sys"}) read_buffer = RenameClockDomains(SyncFIFO(phy_description(8), 4), {"sys": "ftdi"}) self.comb += read_buffer.source.connect(read_fifo.sink) - # Write Fifo (SoC --> Ftdi) + # write fifo (SoC --> FTDI) write_fifo = RenameClockDomains(AsyncFIFO(phy_description(8), fifo_depth), {"write": "sys", "read": "ftdi"}) self.submodules += read_fifo, read_buffer, write_fifo - # - # Sink / Source interfaces - # + # sink / source interfaces self.sink = write_fifo.sink self.source = read_fifo.source - # - # Read / Write Arbitration - # + # read / write arbitration wants_write = Signal() wants_read = Signal() @@ -102,14 +96,13 @@ class FT2232HPHYSynchronous(Module): NextState("READ") ) - # - # Read / Write Actions - # - + # databus tristate data_w = Signal(dw) data_r = Signal(dw) data_oe = Signal() + self.specials += Tristate(pads.data, data_w, data_oe, data_r) + # read / write actions pads.oe_n.reset = 1 pads.rd_n.reset = 1 pads.wr_n.reset = 1 @@ -145,43 +138,35 @@ class FT2232HPHYSynchronous(Module): ) ] - # - # Databus Tristate - # - self.specials += Tristate(pads.data, data_w, data_oe, data_r) - self.debug = Signal(8) - self.comb += self.debug.eq(data_r) - - -class FT2232HPHYAsynchronous(Module): +class FT245PHYAsynchronous(Module): def __init__(self, pads, clk_freq, fifo_depth=32, - read_time=16, - write_time=16): + read_time=128, + write_time=128): dw = flen(pads.data) + self.clk_freq = clk_freq - # - # Read / Write Fifos - # + # timings + tRD = self.ns(30) # RD# active pulse width (t4) + tRDDataSetup = self.ns(14) # RD# to DATA (t3) + tWRDataSetup = self.ns(5) # DATA to WR# active setup time (t8) + tWR = self.ns(30) # WR# active pulse width (t10) + tMultiReg = 2 - # Read Fifo (Ftdi --> SoC) + # read fifo (FTDI --> SoC) read_fifo = SyncFIFO(phy_description(8), fifo_depth) - # Write Fifo (SoC --> Ftdi) + # write fifo (SoC --> FTDI) write_fifo = SyncFIFO(phy_description(8), fifo_depth) self.submodules += read_fifo, write_fifo - # - # Sink / Source interfaces - # + # sink / source interfaces self.sink = write_fifo.sink self.source = read_fifo.source - # - # Read / Write Arbitration - # + # read / write arbitration wants_write = Signal() wants_read = Signal() @@ -233,9 +218,7 @@ class FT2232HPHYAsynchronous(Module): NextState("READ") ) - # - # Databus Tristate - # + # databus tristate data_w = Signal(dw) data_r_async = Signal(dw) data_r = Signal(dw) @@ -245,10 +228,8 @@ class FT2232HPHYAsynchronous(Module): MultiReg(data_r_async, data_r) ] - # - # Read / Write Actions - # - pads.wr_n.reset = 1 + + # read actions pads.rd_n.reset = 1 read_fsm = FSM(reset_state="IDLE") @@ -267,7 +248,7 @@ class FT2232HPHYAsynchronous(Module): read_fsm.act("PULSE_RD_N", pads.rd_n.eq(0), read_counter.ce.eq(1), - If(read_counter.value == 15, # XXX Compute exact value + If(read_counter.value == max((tRD-1), (tRDDataSetup + tMultiReg -1)), NextState("ACQUIRE_DATA") ) ) @@ -282,6 +263,9 @@ class FT2232HPHYAsynchronous(Module): ) ) + # write actions + pads.wr_n.reset = 1 + write_fsm = FSM(reset_state="IDLE") write_counter = Counter(8) self.submodules += write_fsm, write_counter @@ -299,7 +283,7 @@ class FT2232HPHYAsynchronous(Module): data_oe.eq(1), data_w.eq(write_fifo.source.data), write_counter.ce.eq(1), - If(write_counter.value == 5, # XXX Compute exact value + If(write_counter.value == (tWRDataSetup-1), write_counter.reset.eq(1), NextState("PULSE_WR_N") ) @@ -309,7 +293,7 @@ class FT2232HPHYAsynchronous(Module): data_w.eq(write_fifo.source.data), pads.wr_n.eq(0), write_counter.ce.eq(1), - If(write_counter.value == 15, # XXX Compute exact value + If(write_counter.value == (tWR-1), NextState("WAIT_TXE_N") ) ) @@ -319,3 +303,17 @@ class FT2232HPHYAsynchronous(Module): NextState("IDLE") ) ) + + def ns(self, t, margin=True): + clk_period_ns = 1000000000/self.clk_freq + if margin: + t += clk_period_ns/2 + return math.ceil(t/clk_period_ns) + + +def FT245PHY(pads, *args, **kwargs): + # autodetect PHY + if hasattr(pads, "oe_n"): + return FT245PHYSynchronous(pads, *args, **kwargs) + else: + return FT245PHYAsynchronous(pads, *args, **kwargs) diff --git a/misoclib/com/liteusb/test/Makefile b/misoclib/com/liteusb/test/Makefile index 8224e8098..bf90b0741 100644 --- a/misoclib/com/liteusb/test/Makefile +++ b/misoclib/com/liteusb/test/Makefile @@ -3,11 +3,11 @@ PYTHON = python3 CMD = PYTHONPATH=$(MSCDIR) $(PYTHON) -ft2232h_sync_tb: - $(CMD) ft2232h_sync_tb.py +ft245_sync_tb: + $(CMD) ft245_sync_tb.py -ft2232h_async_tb: - $(CMD) ft2232h_async_tb.py +ft245_async_tb: + $(CMD) ft245_async_tb.py core_tb: $(CMD) core_tb.py diff --git a/misoclib/com/liteusb/test/ft2232h_async_tb.py b/misoclib/com/liteusb/test/ft245_async_tb.py similarity index 79% rename from misoclib/com/liteusb/test/ft2232h_async_tb.py rename to misoclib/com/liteusb/test/ft245_async_tb.py index 4af0a6cf8..dcc259923 100644 --- a/misoclib/com/liteusb/test/ft2232h_async_tb.py +++ b/misoclib/com/liteusb/test/ft245_async_tb.py @@ -5,18 +5,22 @@ from migen.fhdl.specials import * from migen.sim.generic import run_simulation from misoclib.com.liteusb.common import * -from misoclib.com.liteusb.phy.ft2232h import FT2232HPHYAsynchronous +from misoclib.com.liteusb.phy.ft245 import FT245PHYAsynchronous from misoclib.com.liteusb.test.common import * # XXX for now use it from liteeth to avoid duplication from misoclib.com.liteeth.test.common import * -class FT2232HAsynchronousModel(Module, RandRun): - def __init__(self, rd_data): - RandRun.__init__(self, 10) +class FT245AsynchronousModel(Module): + def __init__(self, clk_freq, rd_data): + self.clk_freq = clk_freq self.rd_data = [0] + rd_data self.rd_idx = 0 + # timings + self.tRDInactive = self.ns(49) # RXF# inactive after RD# cycle + self.tWRInactive = self.ns(49) # TXE# inactive after WR# cycle + # pads self.data = Signal(8) self.rxf_n = Signal(reset=1) @@ -48,11 +52,10 @@ class FT2232HAsynchronousModel(Module, RandRun): else: if (not selfp.wr_n and self.last_wr_n) and not selfp.txe_n: self.wr_data.append(selfp.data_w) - self.wr_delay = 20 # XXX FIXME + self.wr_delay = self.tWRInactive self.last_wr_n = selfp.wr_n - if self.run: - selfp.txe_n = 0 + selfp.txe_n = 0 def rd_sim(self, selfp): if self.rd_delay: @@ -60,12 +63,9 @@ class FT2232HAsynchronousModel(Module, RandRun): self.rd_delay = self.rd_delay - 1 else: rxf_n = selfp.rxf_n - if self.run: - if self.rd_idx < len(self.rd_data)-1: - self.rd_done = selfp.rxf_n - selfp.rxf_n = 0 - else: - selfp.rxf_n = self.rd_done + if self.rd_idx < len(self.rd_data)-1: + self.rd_done = selfp.rxf_n + selfp.rxf_n = 0 else: selfp.rxf_n = self.rd_done @@ -75,12 +75,11 @@ class FT2232HAsynchronousModel(Module, RandRun): selfp.data_r = self.rd_data[self.rd_idx] self.rd_done = 1 if selfp.rd_n and not self.last_rd_n: - self.rd_delay = 4 # XXX FIXME + self.rd_delay = self.tRDInactive self.last_rd_n = selfp.rd_n def do_simulation(self, selfp): - RandRun.do_simulation(self, selfp) if self.init: selfp.rxf_n = 0 self.wr_data = [] @@ -88,13 +87,21 @@ class FT2232HAsynchronousModel(Module, RandRun): self.wr_sim(selfp) self.rd_sim(selfp) + def ns(self, t, margin=True): + clk_period_ns = 1000000000/self.clk_freq + if margin: + t += clk_period_ns/2 + return math.ceil(t/clk_period_ns) + + test_packet = [i%256 for i in range(128)] class TB(Module): def __init__(self): - self.submodules.model = FT2232HAsynchronousModel(test_packet) - self.submodules.phy = FT2232HPHYAsynchronous(self.model, 50000000) + clk_freq = 50*1000000 + self.submodules.model = FT245AsynchronousModel(clk_freq, test_packet) + self.submodules.phy = FT245PHYAsynchronous(self.model, clk_freq) self.submodules.streamer = PacketStreamer(phy_description(8)) self.submodules.streamer_randomizer = AckRandomizer(phy_description(8), level=10) diff --git a/misoclib/com/liteusb/test/ft2232h_sync_tb.py b/misoclib/com/liteusb/test/ft245_sync_tb.py similarity index 94% rename from misoclib/com/liteusb/test/ft2232h_sync_tb.py rename to misoclib/com/liteusb/test/ft245_sync_tb.py index a17e8086e..ffa2faf34 100644 --- a/misoclib/com/liteusb/test/ft2232h_sync_tb.py +++ b/misoclib/com/liteusb/test/ft245_sync_tb.py @@ -5,13 +5,13 @@ from migen.fhdl.specials import * from migen.sim.generic import run_simulation from misoclib.com.liteusb.common import * -from misoclib.com.liteusb.phy.ft2232h import FT2232HPHYSynchronous +from misoclib.com.liteusb.phy.ft245 import FT245PHYSynchronous from misoclib.com.liteusb.test.common import * # XXX for now use it from liteeth to avoid duplication from misoclib.com.liteeth.test.common import * -class FT2232HSynchronousModel(Module, RandRun): +class FT245SynchronousModel(Module, RandRun): def __init__(self, rd_data): RandRun.__init__(self, 10) self.rd_data = [0] + rd_data @@ -82,8 +82,8 @@ test_packet = [i%256 for i in range(512)] class TB(Module): def __init__(self): - self.submodules.model = FT2232HSynchronousModel(test_packet) - self.submodules.phy = FT2232HPHYSynchronous(self.model) + self.submodules.model = FT245SynchronousModel(test_packet) + self.submodules.phy = FT245PHYSynchronous(self.model) self.submodules.streamer = PacketStreamer(phy_description(8)) self.submodules.streamer_randomizer = AckRandomizer(phy_description(8), level=10)