Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions liteeth/mac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from liteeth.mac.common import *
from liteeth.mac.core import LiteEthMACCore
from liteeth.mac.wishbone import LiteEthMACWishboneInterface
from liteeth.mac.dma import LiteEthMACDMAInterface

# MAC ----------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -79,6 +80,56 @@ def __init__(self, phy, dw,
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):
Expand Down
18 changes: 18 additions & 0 deletions liteeth/mac/dma/__init__.py
Original file line number Diff line number Diff line change
@@ -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 changes: 129 additions & 0 deletions liteeth/mac/dma/reader.py
Original file line number Diff line number Diff line change
@@ -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 changes: 140 additions & 0 deletions liteeth/mac/dma/writer.py
Original file line number Diff line number Diff line change
@@ -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")
)
)
)