mac: Add DMA interface

This commit is contained in:
serg 2022-05-26 19:11:18 +03:00
parent b0e7243123
commit f630a6f8d5
4 changed files with 338 additions and 0 deletions

View File

@ -8,6 +8,7 @@ from liteeth.common import *
from liteeth.mac.common import * from liteeth.mac.common import *
from liteeth.mac.core import LiteEthMACCore from liteeth.mac.core import LiteEthMACCore
from liteeth.mac.wishbone import LiteEthMACWishboneInterface from liteeth.mac.wishbone import LiteEthMACWishboneInterface
from liteeth.mac.dma import LiteEthMACDMAInterface
# MAC ---------------------------------------------------------------------------------------------- # MAC ----------------------------------------------------------------------------------------------
@ -79,6 +80,56 @@ class LiteEthMAC(Module, AutoCSR):
def get_csrs(self): def get_csrs(self):
return self.csrs return self.csrs
# MAC with DMA -------------------------------------------------------------------------------------
class LiteEthMACDMA(Module, AutoCSR):
def __init__(self, phy,
dma_write_port,
dma_read_port,
dma_offset,
with_preamble_crc = True,
nrxslots = 2,
ntxslots = 2,
with_sys_datapath = False):
dw = phy.dw
self.with_dma = CSRConstant(True)
self.rx_slots = CSRConstant(nrxslots)
self.tx_slots = CSRConstant(ntxslots)
self.slot_size = CSRConstant(2**bits_for(eth_mtu))
self.dma_offset = CSRConstant(dma_offset)
self.csrs = []
self.submodules.core = LiteEthMACCore(
phy = phy,
dw = dw,
with_sys_datapath = with_sys_datapath,
with_preamble_crc = with_preamble_crc
)
self.submodules.dma = LiteEthMACDMAInterface(
dw = dw,
write_port = dma_write_port,
read_port = dma_read_port,
offset = dma_offset,
nrxslots = nrxslots,
ntxslots = ntxslots,
slot_size = self.slot_size.constant
)
self.ev = self.dma.ev
self.csrs = self.core.get_csrs() + self.dma.get_csrs()
self.comb += self.core.source.connect(self.dma.sink)
self.comb += self.dma.source.connect(self.core.sink)
def get_csrs(self):
return self.csrs
# MAC Core Crossbar -------------------------------------------------------------------------------- # MAC Core Crossbar --------------------------------------------------------------------------------
class LiteEthMACCoreCrossbar(Module): class LiteEthMACCoreCrossbar(Module):

View File

@ -0,0 +1,18 @@
from migen import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.csr_eventmanager import *
from .writer import LiteEthMACDMAWriter
from .reader import LiteEthMACDMAReader
class LiteEthMACDMAInterface(Module, AutoCSR):
def __init__(self, dw, write_port, read_port, offset, nrxslots, ntxslots, slot_size):
write_offset = offset
read_offset = offset + slot_size * nrxslots
self.submodules.sram_writer = LiteEthMACDMAWriter(dw, nrxslots, slot_size, write_port, write_offset)
self.submodules.sram_reader = LiteEthMACDMAReader(dw, ntxslots, slot_size, read_port, read_offset)
self.submodules.ev = SharedIRQ(self.sram_writer.ev, self.sram_reader.ev)
self.sink, self.source = self.sram_writer.sink, self.sram_reader.source

129
liteeth/mac/dma/reader.py Normal file
View File

@ -0,0 +1,129 @@
from migen import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.csr_eventmanager import *
from liteeth.common import *
from litedram.frontend.dma import LiteDRAMDMAReader
class LiteEthMACDMAReader(Module, AutoCSR):
def __init__(self, dw, nslots, depth, port, offset):
self.source = source = stream.Endpoint(eth_phy_description(dw))
dma_dw = port.data_width
length_bits = bits_for(depth - 1)
slot_bits = bits_for(nslots - 1)
self._start = CSR()
self._ready = CSRStatus()
self._slot = CSRStorage(slot_bits)
self._length = CSRStorage(length_bits)
self.submodules.ev = EventManager()
self.ev.done = EventSourcePulse()
self.ev.finalize()
# # #
# Command FIFO.
_cmd_fifo_layout = [("slot", slot_bits), ("length", length_bits)]
cmd_fifo = stream.SyncFIFO(_cmd_fifo_layout, nslots)
self.submodules += cmd_fifo
self.comb += [
cmd_fifo.sink.valid.eq(self._start.re & self._start.r),
cmd_fifo.sink.slot.eq(self._slot.storage),
cmd_fifo.sink.length.eq(self._length.storage),
self._ready.status.eq(cmd_fifo.sink.ready),
]
length = cmd_fifo.source.length
count = Signal(length_bits, reset_less=True)
# Encode Length to last_be.
length_lsb = length[:log2_int(dw//8)] if (dw != 8) else 0
self.comb += If(source.last,
Case(length_lsb, {
1 : source.last_be.eq(0b00000001),
2 : source.last_be.eq(0b00000010),
3 : source.last_be.eq(0b00000100),
4 : source.last_be.eq(0b00001000),
5 : source.last_be.eq(0b00010000),
6 : source.last_be.eq(0b00100000),
7 : source.last_be.eq(0b01000000),
"default" : source.last_be.eq(2**(dw//8 - 1)),
})
)
# DMA.
start = Signal()
last = Signal()
self.submodules.dma = dma = LiteDRAMDMAReader(port)
# Converter.
conv = stream.StrideConverter(
description_from=[("data", dma_dw)],
description_to=[("data", dw)])
conv = ResetInserter()(conv)
self.submodules += conv
self.comb += conv.source.connect(source, omit={"last", "last_be"}),
# FSM.
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
conv.reset.eq(1),
If(cmd_fifo.source.valid,
start.eq(1),
NextValue(count, 0),
NextState("READ")
)
)
fsm.act("READ",
dma.source.connect(conv.sink),
source.last.eq(count >= length - 1),
If(source.valid & source.ready,
NextValue(count, count + (dw//8)),
If(source.last,
last.eq(1),
NextState("TERMINATE")
)
)
)
fsm.act("TERMINATE",
dma.source.ready.eq(1),
If(dma.rsv_level == 0,
self.ev.done.trigger.eq(1),
cmd_fifo.source.ready.eq(1),
NextState("IDLE")
)
)
# DMA address.
rd_addr_offset = C(offset // (dma_dw//8))
rd_addr = Signal(bits_for(depth // (dma_dw//8) - 1), reset_less=True)
rd_slot = cmd_fifo.source.slot
rd_slot_offset = Signal.like(dma.sink.address)
self.comb += rd_slot_offset.eq(rd_slot * (depth // (dma_dw//8)))
self.comb += dma.sink.address.eq(rd_addr_offset + rd_slot_offset + rd_addr)
self.submodules.dma_fsm = dma_fsm = FSM(reset_state="IDLE")
dma_fsm.act("IDLE",
If(start,
NextValue(rd_addr, 0),
NextState("READ")
)
)
dma_fsm.act("READ",
dma.sink.valid.eq(1),
If(dma.sink.valid & dma.sink.ready,
NextValue(rd_addr, rd_addr + 1)
),
If(last,
NextState("IDLE")
)
)

140
liteeth/mac/dma/writer.py Normal file
View File

@ -0,0 +1,140 @@
from migen import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.csr_eventmanager import *
from liteeth.common import *
from litedram.frontend.dma import LiteDRAMDMAWriter
class LiteEthMACDMAWriter(Module, AutoCSR):
def __init__(self, dw, nslots, depth, port, offset):
self.sink = sink = stream.Endpoint(eth_phy_description(dw))
dma_dw = port.data_width
length_bits = bits_for(depth - 1)
slot_bits = bits_for(nslots - 1)
self._slot = CSRStatus(slot_bits)
self._length = CSRStatus(length_bits)
self._errors = CSRStatus(32)
self.submodules.ev = EventManager()
self.ev.available = EventSourceLevel()
self.ev.finalize()
# # #
errors = self._errors.status
slot = Signal(slot_bits)
length = Signal(length_bits, reset_less=True)
length_inc = Signal(bits_for(dw//8))
# Decode Length increment from from last_be.
self.comb += Case(sink.last_be, {
0b00000001 : length_inc.eq(1),
0b00000010 : length_inc.eq(2),
0b00000100 : length_inc.eq(3),
0b00001000 : length_inc.eq(4),
0b00010000 : length_inc.eq(5),
0b00100000 : length_inc.eq(6),
0b01000000 : length_inc.eq(7),
"default" : length_inc.eq(dw//8)
})
# Status FIFO.
_stat_fifo_layout = [("slot", slot_bits), ("length", length_bits)]
stat_fifo = stream.SyncFIFO(_stat_fifo_layout, nslots)
self.submodules += stat_fifo
# Converter.
conv = stream.StrideConverter(
description_from=[("data", dw)],
description_to=[("data", dma_dw)])
conv = ResetInserter()(conv)
self.submodules += conv
# DMA.
start = Signal()
done = Signal()
self.submodules.dma = dma = LiteDRAMDMAWriter(port)
self.comb += conv.source.connect(dma.sink, omit={"address"}),
# FSM.
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
conv.reset.eq(1),
If(sink.valid,
If(stat_fifo.sink.ready,
start.eq(1),
NextValue(length, 0),
NextState("WRITE")
).Else(
NextValue(errors, errors + 1),
NextState("DISCARD-REMAINING")
)
)
)
fsm.act("WRITE",
sink.connect(conv.sink, omit={"last_be", "error"}),
If(sink.valid & sink.ready,
NextValue(length, length + length_inc),
If(sink.last,
NextState("TERMINATE")
).Elif(length >= eth_mtu,
NextState("DISCARD-REMAINING")
)
)
)
fsm.act("DISCARD-REMAINING",
sink.ready.eq(1),
If(sink.valid & sink.last,
NextState("IDLE")
)
)
fsm.act("TERMINATE",
If(done,
stat_fifo.sink.valid.eq(1),
NextValue(slot, slot + 1),
NextState("IDLE")
)
)
self.comb += [
stat_fifo.sink.slot.eq(slot),
stat_fifo.sink.length.eq(length),
stat_fifo.source.ready.eq(self.ev.available.clear),
self.ev.available.trigger.eq(stat_fifo.source.valid),
self._slot.status.eq(stat_fifo.source.slot),
self._length.status.eq(stat_fifo.source.length),
]
# DMA address.
wr_addr_offset = C(offset // (dma_dw//8))
wr_addr = Signal(bits_for(depth // (dma_dw//8) - 1), reset_less=True)
wr_slot_offset = Signal.like(dma.sink.address)
self.comb += wr_slot_offset.eq(slot * (depth // (dma_dw//8)))
self.comb += dma.sink.address.eq(wr_addr_offset + wr_slot_offset + wr_addr)
self.submodules.dma_fsm = dma_fsm = FSM(reset_state="IDLE")
dma_fsm.act("IDLE",
done.eq(1),
If(start,
NextValue(wr_addr, 0),
NextState("WRITE")
)
)
dma_fsm.act("WRITE",
If(dma.sink.valid & dma.sink.ready,
NextValue(wr_addr, wr_addr + 1),
If(dma.sink.last,
NextState("IDLE")
)
)
)