From: Florent Kermarrec Date: Fri, 1 May 2015 14:11:15 +0000 (+0200) Subject: liteusb: continue refactoring (virtual UART and DMA working on minispartan6) X-Git-Tag: 24jan2021_ls180~2283 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=603b4cdc8cb3cbbfe1abc2e24a0d4e6e58c421f8;p=litex.git 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 --- diff --git a/misoclib/com/liteusb/common.py b/misoclib/com/liteusb/common.py index df3d7482..2cbf00e6 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 b416a983..9ecd835c 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 e342712e..59440df5 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 bb4c28ad..43c97b01 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 a9a96701..79f7ab67 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 6e551f00..648d6763 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/ft2232h.py deleted file mode 100644 index 92b4219b..00000000 --- a/misoclib/com/liteusb/phy/ft2232h.py +++ /dev/null @@ -1,321 +0,0 @@ -from migen.fhdl.std import * -from migen.flow.actor import * -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): - dw = flen(pads.data) - - # - # Read / Write Fifos - # - - # 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 = RenameClockDomains(AsyncFIFO(phy_description(8), fifo_depth), - {"write": "sys", "read": "ftdi"}) - - self.submodules += read_fifo, read_buffer, 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.comb += [ - txe_n.eq(pads.txe_n), - rxf_n.eq(pads.rxf_n), - 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) - - data_w_accepted = Signal(reset=1) - - fsm = FSM(reset_state="READ") - self.submodules += RenameClockDomains(fsm, {"sys": "ftdi"}) - - fsm.act("READ", - read_time_en.eq(1), - If(wants_write, - If(~wants_read | max_read_time, - NextState("RTW") - ) - ) - ) - fsm.act("RTW", - NextState("WRITE") - ) - fsm.act("WRITE", - write_time_en.eq(1), - If(wants_read, - If(~wants_write | max_write_time, - NextState("WTR") - ) - ), - write_fifo.source.ack.eq(wants_write & data_w_accepted) - ) - fsm.act("WTR", - NextState("READ") - ) - - # - # Read / Write Actions - # - - data_w = Signal(dw) - data_r = Signal(dw) - data_oe = Signal() - - pads.oe_n.reset = 1 - pads.rd_n.reset = 1 - pads.wr_n.reset = 1 - - self.sync.ftdi += [ - If(fsm.ongoing("READ"), - data_oe.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.rd_n.eq(1), - pads.wr_n.eq(~wants_write), - - data_w_accepted.eq(~txe_n) - - ).Else( - data_oe.eq(1), - - pads.oe_n.eq(~fsm.ongoing("WTR")), - pads.rd_n.eq(1), - pads.wr_n.eq(1) - ), - read_buffer.sink.stb.eq(~pads.rd_n & ~rxf_n), - read_buffer.sink.data.eq(data_r), - If(~txe_n & data_w_accepted, - data_w.eq(write_fifo.source.data) - ) - ] - - # - # 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): - 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/phy/ft245.py b/misoclib/com/liteusb/phy/ft245.py new file mode 100644 index 00000000..bed5f5d6 --- /dev/null +++ b/misoclib/com/liteusb/phy/ft245.py @@ -0,0 +1,319 @@ +import math + +from migen.fhdl.std import * +from migen.flow.actor import * +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 FT245PHYSynchronous(Module): + def __init__(self, pads, clk_freq, + fifo_depth=32, + read_time=128, + write_time=128): + dw = flen(pads.data) + + # 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 = RenameClockDomains(AsyncFIFO(phy_description(8), fifo_depth), + {"write": "sys", "read": "ftdi"}) + + self.submodules += read_fifo, read_buffer, 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.comb += [ + txe_n.eq(pads.txe_n), + rxf_n.eq(pads.rxf_n), + 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) + + data_w_accepted = Signal(reset=1) + + fsm = FSM(reset_state="READ") + self.submodules += RenameClockDomains(fsm, {"sys": "ftdi"}) + + fsm.act("READ", + read_time_en.eq(1), + If(wants_write, + If(~wants_read | max_read_time, + NextState("RTW") + ) + ) + ) + fsm.act("RTW", + NextState("WRITE") + ) + fsm.act("WRITE", + write_time_en.eq(1), + If(wants_read, + If(~wants_write | max_write_time, + NextState("WTR") + ) + ), + write_fifo.source.ack.eq(wants_write & data_w_accepted) + ) + fsm.act("WTR", + NextState("READ") + ) + + # 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 + + self.sync.ftdi += [ + If(fsm.ongoing("READ"), + data_oe.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.rd_n.eq(1), + pads.wr_n.eq(~wants_write), + + data_w_accepted.eq(~txe_n) + + ).Else( + data_oe.eq(1), + + pads.oe_n.eq(~fsm.ongoing("WTR")), + pads.rd_n.eq(1), + pads.wr_n.eq(1) + ), + read_buffer.sink.stb.eq(~pads.rd_n & ~rxf_n), + read_buffer.sink.data.eq(data_r), + If(~txe_n & data_w_accepted, + data_w.eq(write_fifo.source.data) + ) + ] + + +class FT245PHYAsynchronous(Module): + def __init__(self, pads, clk_freq, + fifo_depth=32, + read_time=128, + write_time=128): + dw = flen(pads.data) + self.clk_freq = clk_freq + + # 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 = 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 actions + 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 == max((tRD-1), (tRDDataSetup + tMultiReg -1)), + 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 actions + pads.wr_n.reset = 1 + + 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 == (tWRDataSetup-1), + 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 == (tWR-1), + NextState("WAIT_TXE_N") + ) + ) + write_fsm.act("WAIT_TXE_N", + If(txe_n, + write_fifo.source.ack.eq(1), + 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 8224e809..bf90b074 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/ft2232h_async_tb.py deleted file mode 100644 index 4af0a6cf..00000000 --- a/misoclib/com/liteusb/test/ft2232h_async_tb.py +++ /dev/null @@ -1,132 +0,0 @@ -from migen.fhdl.std import * -from migen.flow.actor import * -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.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) - self.rd_data = [0] + rd_data - self.rd_idx = 0 - - # pads - self.data = Signal(8) - self.rxf_n = Signal(reset=1) - self.txe_n = Signal(reset=1) - self.rd_n = Signal(reset=1) - self.wr_n = Signal(reset=1) - - self.init = True - self.wr_data = [] - self.wait_wr_n = False - self.rd_done = 0 - - - self.data_w = Signal(8) - self.data_r = Signal(8) - - 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 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 self.run: - selfp.txe_n = 0 - - def rd_sim(self, selfp): - 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 - - 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) - if self.init: - selfp.rxf_n = 0 - self.wr_data = [] - self.init = False - self.wr_sim(selfp) - self.rd_sim(selfp) - -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) - - self.submodules.streamer = PacketStreamer(phy_description(8)) - self.submodules.streamer_randomizer = AckRandomizer(phy_description(8), level=10) - - 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), - self.phy.sink.stb.eq(self.streamer_randomizer.source.stb), - self.phy.sink.data.eq(self.streamer_randomizer.source.data), - self.streamer_randomizer.source.ack.eq(self.phy.sink.ack), - - self.logger_randomizer.sink.stb.eq(self.phy.source.stb), - self.logger_randomizer.sink.data.eq(self.phy.source.data), - self.phy.source.ack.eq(self.logger_randomizer.sink.ack), - Record.connect(self.logger_randomizer.source, self.logger.sink) - ] - - def gen_simulation(self, selfp): - yield from self.streamer.send(Packet(test_packet)) - 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) - print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e)) - - -def main(): - run_simulation(TB(), ncycles=8000, vcd_name="my.vcd", keep_files=True) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/misoclib/com/liteusb/test/ft2232h_sync_tb.py b/misoclib/com/liteusb/test/ft2232h_sync_tb.py deleted file mode 100644 index a17e8086..00000000 --- a/misoclib/com/liteusb/test/ft2232h_sync_tb.py +++ /dev/null @@ -1,127 +0,0 @@ -from migen.fhdl.std import * -from migen.flow.actor import * -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.test.common import * - -# XXX for now use it from liteeth to avoid duplication -from misoclib.com.liteeth.test.common import * - -class FT2232HSynchronousModel(Module, RandRun): - def __init__(self, rd_data): - RandRun.__init__(self, 10) - self.rd_data = [0] + rd_data - self.rd_idx = 0 - - # pads - self.data = Signal(8) - self.rxf_n = Signal(reset=1) - 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 = [] - self.wait_wr_n = False - self.rd_done = 0 - - - self.data_w = Signal(8) - self.data_r = Signal(8) - - self.specials += Tristate(self.data, self.data_r, ~self.oe_n, self.data_w) - - 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 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 - 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 - - def do_simulation(self, selfp): - RandRun.do_simulation(self, selfp) - if self.init: - selfp.rxf_n = 0 - self.wr_data = [] - self.init = False - self.wr_sim(selfp) - self.rd_sim(selfp) - -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.streamer = PacketStreamer(phy_description(8)) - self.submodules.streamer_randomizer = AckRandomizer(phy_description(8), level=10) - - 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), - self.phy.sink.stb.eq(self.streamer_randomizer.source.stb), - self.phy.sink.data.eq(self.streamer_randomizer.source.data), - self.streamer_randomizer.source.ack.eq(self.phy.sink.ack), - - self.logger_randomizer.sink.stb.eq(self.phy.source.stb), - self.logger_randomizer.sink.data.eq(self.phy.source.data), - self.phy.source.ack.eq(self.logger_randomizer.sink.ack), - 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): - 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:]) - print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e)) - - -def main(): - run_simulation(TB(), ncycles=8000, vcd_name="my.vcd", keep_files=True) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/misoclib/com/liteusb/test/ft245_async_tb.py b/misoclib/com/liteusb/test/ft245_async_tb.py new file mode 100644 index 00000000..dcc25992 --- /dev/null +++ b/misoclib/com/liteusb/test/ft245_async_tb.py @@ -0,0 +1,139 @@ +from migen.fhdl.std import * +from migen.flow.actor import * +from migen.fhdl.specials import * + +from migen.sim.generic import run_simulation + +from misoclib.com.liteusb.common import * +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 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) + self.txe_n = Signal(reset=1) + self.rd_n = Signal(reset=1) + self.wr_n = Signal(reset=1) + + self.init = True + self.wr_data = [] + self.wait_wr_n = False + self.rd_done = 0 + + + self.data_w = Signal(8) + self.data_r = Signal(8) + + 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 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 = self.tWRInactive + self.last_wr_n = selfp.wr_n + + selfp.txe_n = 0 + + def rd_sim(self, selfp): + if self.rd_delay: + selfp.rxf_n = 1 + self.rd_delay = self.rd_delay - 1 + else: + rxf_n = selfp.rxf_n + 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 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 = self.tRDInactive + + self.last_rd_n = selfp.rd_n + + def do_simulation(self, selfp): + if self.init: + selfp.rxf_n = 0 + self.wr_data = [] + self.init = False + 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): + 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) + + 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), + self.phy.sink.stb.eq(self.streamer_randomizer.source.stb), + self.phy.sink.data.eq(self.streamer_randomizer.source.data), + self.streamer_randomizer.source.ack.eq(self.phy.sink.ack), + + self.logger_randomizer.sink.stb.eq(self.phy.source.stb), + self.logger_randomizer.sink.data.eq(self.phy.source.data), + self.phy.source.ack.eq(self.logger_randomizer.sink.ack), + Record.connect(self.logger_randomizer.source, self.logger.sink) + ] + + def gen_simulation(self, selfp): + yield from self.streamer.send(Packet(test_packet)) + 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) + print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e)) + + +def main(): + run_simulation(TB(), ncycles=8000, vcd_name="my.vcd", keep_files=True) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/misoclib/com/liteusb/test/ft245_sync_tb.py b/misoclib/com/liteusb/test/ft245_sync_tb.py new file mode 100644 index 00000000..ffa2faf3 --- /dev/null +++ b/misoclib/com/liteusb/test/ft245_sync_tb.py @@ -0,0 +1,127 @@ +from migen.fhdl.std import * +from migen.flow.actor import * +from migen.fhdl.specials import * + +from migen.sim.generic import run_simulation + +from misoclib.com.liteusb.common import * +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 FT245SynchronousModel(Module, RandRun): + def __init__(self, rd_data): + RandRun.__init__(self, 10) + self.rd_data = [0] + rd_data + self.rd_idx = 0 + + # pads + self.data = Signal(8) + self.rxf_n = Signal(reset=1) + 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 = [] + self.wait_wr_n = False + self.rd_done = 0 + + + self.data_w = Signal(8) + self.data_r = Signal(8) + + self.specials += Tristate(self.data, self.data_r, ~self.oe_n, self.data_w) + + 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 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 + 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 + + def do_simulation(self, selfp): + RandRun.do_simulation(self, selfp) + if self.init: + selfp.rxf_n = 0 + self.wr_data = [] + self.init = False + self.wr_sim(selfp) + self.rd_sim(selfp) + +test_packet = [i%256 for i in range(512)] + + +class TB(Module): + def __init__(self): + 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) + + 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), + self.phy.sink.stb.eq(self.streamer_randomizer.source.stb), + self.phy.sink.data.eq(self.streamer_randomizer.source.data), + self.streamer_randomizer.source.ack.eq(self.phy.sink.ack), + + self.logger_randomizer.sink.stb.eq(self.phy.source.stb), + self.logger_randomizer.sink.data.eq(self.phy.source.data), + self.phy.source.ack.eq(self.logger_randomizer.sink.ack), + 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): + 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:]) + print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e)) + + +def main(): + run_simulation(TB(), ncycles=8000, vcd_name="my.vcd", keep_files=True) + +if __name__ == "__main__": + main() \ No newline at end of file