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.core import LiteEthMACCore
|
||||
from liteeth.mac.wishbone import LiteEthMACWishboneInterface
|
||||
from liteeth.mac.dma import LiteEthMACDMAInterface
|
||||
|
||||
# MAC ----------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -79,6 +80,56 @@ class LiteEthMAC(Module, AutoCSR):
|
|||
def get_csrs(self):
|
||||
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 --------------------------------------------------------------------------------
|
||||
|
||||
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