soc/cores: add simple DMA with WishboneDMAReader/WishboneDMAWriter.

This commit is contained in:
Florent Kermarrec 2020-06-24 10:17:40 +02:00
parent d7cc7d2ac6
commit bc64e35480
1 changed files with 201 additions and 0 deletions

201
litex/soc/cores/dma.py Normal file
View File

@ -0,0 +1,201 @@
# This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD
"""Direct Memory Access (DMA) reader and writer modules."""
from migen import *
from litex.gen.common import reverse_bytes
from litex.soc.interconnect.csr import *
from litex.soc.interconnect import stream
from litex.soc.interconnect import wishbone
# Helpers ------------------------------------------------------------------------------------------
def format_bytes(s, endianness):
return {"big": s, "little": reverse_bytes(s)}[endianness]
# WishboneDMAReader --------------------------------------------------------------------------------
class WishboneDMAReader(Module, AutoCSR):
"""Read data from Wishbone MMAP memory.
For every address written to the sink, one word will be produced on the source.
Parameters
----------
bus : bus
Wishbone bus of the SoC to read from.
Attributes
----------
sink : Record("address")
Sink for MMAP addresses to be read.
source : Record("data")
Source for MMAP word results from reading.
"""
def __init__(self, bus, endianness="little", with_csr=False):
assert isinstance(bus, wishbone.Interface)
self.bus = bus
self.sink = sink = stream.Endpoint([("address", bus.adr_width)])
self.source = source = stream.Endpoint([("data", bus.data_width)])
# # #
data = Signal(bus.data_width)
self.submodules.fsm = fsm = FSM(reset_state="BUS-READ")
fsm.act("BUS-READ",
bus.stb.eq(sink.valid),
bus.cyc.eq(sink.valid),
bus.we.eq(0),
bus.sel.eq(2**(bus.data_width//8)-1),
bus.adr.eq(sink.address),
If(bus.stb & bus.ack,
NextValue(data, format_bytes(bus.dat_r, endianness)),
NextState("SOURCE-WRITE")
)
)
fsm.act("SOURCE-WRITE",
source.valid.eq(1),
source.data.eq(data),
If(source.ready,
sink.ready.eq(1),
NextState("BUS-READ")
)
)
if with_csr:
self.add_csr()
def add_csr(self):
self._base = CSRStorage(32)
self._length = CSRStorage(32)
self._enable = CSRStorage()
self._done = CSRStatus()
self._loop = CSRStorage()
self._offset = CSRStatus(32)
# # #
shift = log2_int(self.bus.data_width//8)
base = Signal(self.bus.adr_width)
offset = Signal(self.bus.adr_width)
length = Signal(self.bus.adr_width)
self.comb += base.eq(self._base.storage[shift:])
self.comb += length.eq(self._length.storage[shift:])
self.comb += self._offset.status.eq(offset)
fsm = FSM(reset_state="IDLE")
fsm = ResetInserter()(fsm)
self.submodules += fsm
self.comb += fsm.reset.eq(~self._enable.storage)
fsm.act("IDLE",
NextValue(offset, 0),
NextState("RUN"),
)
fsm.act("RUN",
self.sink.valid.eq(1),
self.sink.address.eq(base + offset),
If(self.sink.ready,
NextValue(offset, offset + 1),
If(offset == (length - 1),
If(self._loop.storage,
NextValue(offset, 0)
).Else(
NextState("DONE")
)
)
)
)
fsm.act("DONE",
self._done.status.eq(1)
)
# WishboneDMAWriter --------------------------------------------------------------------------------
class WishboneDMAWriter(Module, AutoCSR):
"""Write data to Wishbone MMAP memory.
Parameters
----------
bus : bus
Wishbone bus of the SoC to read from.
Attributes
----------
sink : Record("address", "data")
Sink for MMAP addresses/datas to be written.
"""
def __init__(self, bus, endianness="little", with_csr=False):
assert isinstance(bus, wishbone.Interface)
self.bus = bus
self.sink = sink = stream.Endpoint([("address", bus.adr_width), ("data", bus.data_width)])
# # #
data = Signal(bus.data_width)
self.comb += [
bus.stb.eq(sink.valid),
bus.cyc.eq(sink.valid),
bus.we.eq(1),
bus.sel.eq(2**(bus.data_width//8)-1),
bus.adr.eq(sink.address),
bus.dat_w.eq(format_bytes(sink.data, endianness)),
sink.ready.eq(bus.ack),
]
if with_csr:
self.add_csr()
def add_csr(self):
self._sink = self.sink
self.sink = stream.Endpoint([("data", self.bus.data_width)])
self._base = CSRStorage(32)
self._length = CSRStorage(32)
self._enable = CSRStorage()
self._done = CSRStatus()
self._loop = CSRStorage()
# # #
shift = log2_int(self.bus.data_width//8)
base = Signal(self.bus.adr_width)
offset = Signal(self.bus.adr_width)
length = Signal(self.bus.adr_width)
self.comb += base.eq(self._base.storage[shift:])
self.comb += length.eq(self._length.storage[shift:])
fsm = FSM(reset_state="IDLE")
fsm = ResetInserter()(fsm)
self.submodules += fsm
self.comb += fsm.reset.eq(~self._enable.storage)
fsm.act("IDLE",
self.sink.ready.eq(1),
NextValue(offset, 0),
NextState("RUN"),
)
fsm.act("RUN",
self._sink.valid.eq(self.sink.valid),
self._sink.data.eq(self.sink.data),
self._sink.address.eq(base + offset),
self.sink.ready.eq(self._sink.ready),
If(self.sink.valid & self.sink.ready,
NextValue(offset, offset + 1),
If(offset == (length - 1),
If(self._loop.storage,
NextValue(offset, 0)
).Else(
NextState("DONE")
)
)
)
)
fsm.act("DONE",
self._done.status.eq(1)
)