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
This commit is contained in:
Florent Kermarrec 2015-05-01 16:11:15 +02:00
parent 8aa3fb3eb7
commit 603b4cdc8c
10 changed files with 141 additions and 159 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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