From 28c50112a40707ae3979c112bb6f183bac506163 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 28 Apr 2015 19:00:13 +0200 Subject: [PATCH] liteusb: add FT2232HPHYAsynchronous PHY (Minispartan6+, Pipistrello), needs more simulations and on-board tests --- misoclib/com/liteusb/phy/ft2232h.py | 239 +++++++++++++++--- misoclib/com/liteusb/test/Makefile | 10 +- .../{ft2232h_tb.py => ft2232h_async_tb.py} | 93 ++++--- 3 files changed, 259 insertions(+), 83 deletions(-) rename misoclib/com/liteusb/test/{ft2232h_tb.py => ft2232h_async_tb.py} (61%) diff --git a/misoclib/com/liteusb/phy/ft2232h.py b/misoclib/com/liteusb/phy/ft2232h.py index 5a325656c..92b4219ba 100644 --- a/misoclib/com/liteusb/phy/ft2232h.py +++ b/misoclib/com/liteusb/phy/ft2232h.py @@ -1,13 +1,34 @@ from migen.fhdl.std import * from migen.flow.actor import * -from migen.actorlib.fifo import AsyncFIFO +from migen.actorlib.fifo import SyncFIFO, AsyncFIFO from migen.fhdl.specials import * +from migen.genlib.cdc import MultiReg from misoclib.com.liteusb.common import * +def anti_starvation(module, timeout): + en = Signal() + max_time = Signal() + if timeout: + t = timeout - 1 + time = Signal(max=t+1) + module.comb += max_time.eq(time == 0) + module.sync += If(~en, + time.eq(t) + ).Elif(~max_time, + time.eq(time - 1) + ) + else: + module.comb += max_time.eq(0) + return en, max_time + + class FT2232HPHYSynchronous(Module): - def __init__(self, pads, fifo_depth=32, read_time=16, write_time=16): + def __init__(self, pads, + fifo_depth=32, + read_time=16, + write_time=16): dw = flen(pads.data) # @@ -15,14 +36,14 @@ class FT2232HPHYSynchronous(Module): # # Read Fifo (Ftdi --> SoC) - read_fifo = RenameClockDomains(AsyncFIFO(phy_layout, fifo_depth), + read_fifo = RenameClockDomains(AsyncFIFO(phy_description(8), fifo_depth), {"write": "ftdi", "read": "sys"}) - read_buffer = RenameClockDomains(SyncFIFO(phy_layout, 4), + 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 = RenameClockDomains(AsyncFIFO(phy_layout, fifo_depth), + write_fifo = RenameClockDomains(AsyncFIFO(phy_description(8), fifo_depth), {"write": "sys", "read": "ftdi"}) self.submodules += read_fifo, read_buffer, write_fifo @@ -49,24 +70,8 @@ class FT2232HPHYSynchronous(Module): wants_read.eq(~rxf_n & read_fifo.sink.ack), ] - def anti_starvation(timeout): - en = Signal() - max_time = Signal() - if timeout: - t = timeout - 1 - time = Signal(max=t+1) - self.comb += max_time.eq(time == 0) - self.sync += If(~en, - time.eq(t) - ).Elif(~max_time, - time.eq(time - 1) - ) - else: - self.comb += max_time.eq(0) - return en, max_time - - read_time_en, max_read_time = anti_starvation(read_time) - write_time_en, max_write_time = anti_starvation(write_time) + read_time_en, max_read_time = anti_starvation(self, read_time) + write_time_en, max_write_time = anti_starvation(self, write_time) data_w_accepted = Signal(reset=1) @@ -76,7 +81,9 @@ class FT2232HPHYSynchronous(Module): fsm.act("READ", read_time_en.eq(1), If(wants_write, - If(~wants_read | max_read_time, NextState("RTW")) + If(~wants_read | max_read_time, + NextState("RTW") + ) ) ) fsm.act("RTW", @@ -85,7 +92,9 @@ class FT2232HPHYSynchronous(Module): fsm.act("WRITE", write_time_en.eq(1), If(wants_read, - If(~wants_write | max_write_time, NextState("WTR")) + If(~wants_write | max_write_time, + NextState("WTR") + ) ), write_fifo.source.ack.eq(wants_write & data_w_accepted) ) @@ -101,12 +110,7 @@ class FT2232HPHYSynchronous(Module): data_r = Signal(dw) data_oe = Signal() - if hasattr(pads, "oe_n"): - pads_oe_n = pads.oe_n - else: - pads_oe_n = Signal() - - pads_oe_n.reset = 1 + pads.oe_n.reset = 1 pads.rd_n.reset = 1 pads.wr_n.reset = 1 @@ -114,14 +118,14 @@ class FT2232HPHYSynchronous(Module): If(fsm.ongoing("READ"), data_oe.eq(0), - pads_oe_n.eq(0), + pads.oe_n.eq(0), pads.rd_n.eq(~wants_read), pads.wr_n.eq(1) ).Elif(fsm.ongoing("WRITE"), data_oe.eq(1), - pads_oe_n.eq(1), + pads.oe_n.eq(1), pads.rd_n.eq(1), pads.wr_n.eq(~wants_write), @@ -130,7 +134,7 @@ class FT2232HPHYSynchronous(Module): ).Else( data_oe.eq(1), - pads_oe_n.eq(~fsm.ongoing("WTR")), + pads.oe_n.eq(~fsm.ongoing("WTR")), pads.rd_n.eq(1), pads.wr_n.eq(1) ), @@ -148,3 +152,170 @@ class FT2232HPHYSynchronous(Module): self.debug = Signal(8) self.comb += self.debug.eq(data_r) + + +class FT2232HPHYAsynchronous(Module): + def __init__(self, pads, clk_freq, + fifo_depth=32, + read_time=16, + write_time=16): + dw = flen(pads.data) + + # + # Read / Write Fifos + # + + # Read Fifo (Ftdi --> SoC) + read_fifo = SyncFIFO(phy_description(8), fifo_depth) + + # Write Fifo (SoC --> Ftdi) + write_fifo = SyncFIFO(phy_description(8), fifo_depth) + + self.submodules += read_fifo, write_fifo + + # + # Sink / Source interfaces + # + self.sink = write_fifo.sink + self.source = read_fifo.source + + # + # Read / Write Arbitration + # + wants_write = Signal() + wants_read = Signal() + + txe_n = Signal() + rxf_n = Signal() + + self.specials += [ + MultiReg(pads.txe_n, txe_n), + MultiReg(pads.rxf_n, rxf_n) + ] + + self.comb += [ + wants_write.eq(~txe_n & write_fifo.source.stb), + wants_read.eq(~rxf_n & read_fifo.sink.ack), + ] + + read_time_en, max_read_time = anti_starvation(self, read_time) + write_time_en, max_write_time = anti_starvation(self, write_time) + + fsm = FSM(reset_state="READ") + self.submodules += fsm + + read_done = Signal() + write_done = Signal() + commuting = Signal() + + fsm.act("READ", + read_time_en.eq(1), + If(wants_write & read_done, + If(~wants_read | max_read_time, + commuting.eq(1), + NextState("RTW") + ) + ) + ) + fsm.act("RTW", + NextState("WRITE") + ) + fsm.act("WRITE", + write_time_en.eq(1), + If(wants_read & write_done, + If(~wants_write | max_write_time, + commuting.eq(1), + NextState("WTR") + ) + ) + ) + fsm.act("WTR", + NextState("READ") + ) + + # + # Databus Tristate + # + data_w = Signal(dw) + data_r_async = Signal(dw) + data_r = Signal(dw) + data_oe = Signal() + self.specials += [ + Tristate(pads.data, data_w, data_oe, data_r_async), + MultiReg(data_r_async, data_r) + ] + + # + # Read / Write Actions + # + pads.wr_n.reset = 1 + pads.rd_n.reset = 1 + + read_fsm = FSM(reset_state="IDLE") + read_counter = Counter(8) + self.submodules += read_fsm, read_counter + + read_fsm.act("IDLE", + read_done.eq(1), + read_counter.reset.eq(1), + If(fsm.ongoing("READ") & wants_read, + If(~commuting, + NextState("PULSE_RD_N") + ) + ) + ) + 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 + NextState("ACQUIRE_DATA") + ) + ) + read_fsm.act("ACQUIRE_DATA", + read_fifo.sink.stb.eq(1), + read_fifo.sink.data.eq(data_r), + NextState("WAIT_RXF_N") + ) + read_fsm.act("WAIT_RXF_N", + If(rxf_n, + NextState("IDLE") + ) + ) + + write_fsm = FSM(reset_state="IDLE") + write_counter = Counter(8) + self.submodules += write_fsm, write_counter + + write_fsm.act("IDLE", + write_done.eq(1), + write_counter.reset.eq(1), + If(fsm.ongoing("WRITE") & wants_write, + If(~commuting, + NextState("SET_DATA") + ) + ) + ) + write_fsm.act("SET_DATA", + 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 + write_counter.reset.eq(1), + NextState("PULSE_WR_N") + ) + ) + write_fsm.act("PULSE_WR_N", + data_oe.eq(1), + 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 + NextState("WAIT_TXE_N") + ) + ) + write_fsm.act("WAIT_TXE_N", + If(txe_n, + write_fifo.source.ack.eq(1), + NextState("IDLE") + ) + ) diff --git a/misoclib/com/liteusb/test/Makefile b/misoclib/com/liteusb/test/Makefile index 6b0ad57be..8224e8098 100644 --- a/misoclib/com/liteusb/test/Makefile +++ b/misoclib/com/liteusb/test/Makefile @@ -3,5 +3,11 @@ PYTHON = python3 CMD = PYTHONPATH=$(MSCDIR) $(PYTHON) -ft2232h_tb: - $(CMD) ft2232h_tb.py +ft2232h_sync_tb: + $(CMD) ft2232h_sync_tb.py + +ft2232h_async_tb: + $(CMD) ft2232h_async_tb.py + +core_tb: + $(CMD) core_tb.py diff --git a/misoclib/com/liteusb/test/ft2232h_tb.py b/misoclib/com/liteusb/test/ft2232h_async_tb.py similarity index 61% rename from misoclib/com/liteusb/test/ft2232h_tb.py rename to misoclib/com/liteusb/test/ft2232h_async_tb.py index 1dd602926..4af0a6cf8 100644 --- a/misoclib/com/liteusb/test/ft2232h_tb.py +++ b/misoclib/com/liteusb/test/ft2232h_async_tb.py @@ -5,19 +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.ft2232h import FT2232HPHYAsynchronous from misoclib.com.liteusb.test.common import * # XXX for now use it from liteeth to avoid duplication from misoclib.com.liteeth.test.common import * - -def phy_description(): - payload_layout = [("data", 8)] - return EndpointDescription(payload_layout, packetized=True) - - -class FT2232HSynchronousModel(Module, RandRun): +class FT2232HAsynchronousModel(Module, RandRun): def __init__(self, rd_data): RandRun.__init__(self, 10) self.rd_data = [0] + rd_data @@ -29,9 +23,6 @@ class FT2232HSynchronousModel(Module, RandRun): self.txe_n = Signal(reset=1) self.rd_n = Signal(reset=1) self.wr_n = Signal(reset=1) - self.oe_n = Signal(reset=1) - self.siwua = Signal() - self.pwren_n = Signal(reset=1) self.init = True self.wr_data = [] @@ -42,37 +33,51 @@ class FT2232HSynchronousModel(Module, RandRun): self.data_w = Signal(8) self.data_r = Signal(8) - self.specials += Tristate(self.data, self.data_r, ~self.oe_n, self.data_w) + self.specials += Tristate(self.data, self.data_r, ~self.rd_n, self.data_w) + + self.last_wr_n = 1 + self.last_rd_n = 1 + + self.wr_delay = 0 + self.rd_delay = 0 def wr_sim(self, selfp): - if not selfp.wr_n and not selfp.txe_n: - self.wr_data.append(selfp.data_w) - self.wait_wr_n = False + if self.wr_delay: + selfp.txe_n = 1 + self.wr_delay = self.wr_delay - 1 + 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.last_wr_n = selfp.wr_n - if not self.wait_wr_n: if self.run: - selfp.txe_n = 1 - else: - if selfp.txe_n: - self.wait_wr_n = True selfp.txe_n = 0 def rd_sim(self, selfp): - 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 + if self.rd_delay: + selfp.rxf_n = 1 + 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 else: selfp.rxf_n = self.rd_done - else: - selfp.rxf_n = self.rd_done - if not selfp.rd_n and not selfp.oe_n: - if self.rd_idx < len(self.rd_data)-1: - self.rd_idx += not rxf_n - selfp.data_r = self.rd_data[self.rd_idx] - self.rd_done = 1 + if not selfp.rd_n and self.last_rd_n: + if self.rd_idx < len(self.rd_data)-1: + self.rd_idx += not rxf_n + 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.last_rd_n = selfp.rd_n def do_simulation(self, selfp): RandRun.do_simulation(self, selfp) @@ -83,19 +88,19 @@ class FT2232HSynchronousModel(Module, RandRun): self.wr_sim(selfp) self.rd_sim(selfp) -test_packet = [i%256 for i in range(512)] +test_packet = [i%256 for i in range(128)] class TB(Module): def __init__(self): - self.submodules.model = FT2232HSynchronousModel(test_packet) - self.submodules.phy = FT2232HPHYSynchronous(self.model) + self.submodules.model = FT2232HAsynchronousModel(test_packet) + self.submodules.phy = FT2232HPHYAsynchronous(self.model, 50000000) - self.submodules.streamer = PacketStreamer(phy_description()) - self.submodules.streamer_randomizer = AckRandomizer(phy_description(), level=10) + self.submodules.streamer = PacketStreamer(phy_description(8)) + self.submodules.streamer_randomizer = AckRandomizer(phy_description(8), level=10) - self.submodules.logger_randomizer = AckRandomizer(phy_description(), level=10) - self.submodules.logger = PacketLogger(phy_description()) + self.submodules.logger_randomizer = AckRandomizer(phy_description(8), level=10) + self.submodules.logger = PacketLogger(phy_description(8)) self.comb += [ Record.connect(self.streamer.source, self.streamer_randomizer.sink), @@ -109,20 +114,14 @@ class TB(Module): Record.connect(self.logger_randomizer.source, self.logger.sink) ] - # Use sys_clk as ftdi_clk in simulation - self.comb += [ - ClockSignal("ftdi").eq(ClockSignal()), - ResetSignal("ftdi").eq(ResetSignal()) - ] - def gen_simulation(self, selfp): yield from self.streamer.send(Packet(test_packet)) - for i in range(2000): + for i in range(4000): yield s, l, e = check(test_packet, self.model.wr_data) print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e)) - s, l, e = check(test_packet, self.logger.packet[1:]) + s, l, e = check(test_packet, self.logger.packet) print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e))