mac: Add DMA interface
This commit is contained in:
parent
b0e7243123
commit
f630a6f8d5
|
@ -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):
|
||||||
|
|
|
@ -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
|
|
@ -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")
|
||||||
|
)
|
||||||
|
)
|
|
@ -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")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
Loading…
Reference in New Issue