soc/cores: remove liteeth_mini and use liteeth

This commit is contained in:
Florent Kermarrec 2015-11-14 03:22:43 +01:00
parent 16ba646b1b
commit a2aa5726bf
24 changed files with 7 additions and 1808 deletions

View file

@ -13,9 +13,9 @@ from litex.soc.integration.soc_core import mem_decoder
from litex.soc.integration.soc_sdram import *
from litex.soc.integration.builder import *
# TODO: use liteeth
from litex.soc.cores.liteeth_mini.phy import LiteEthPHY
from litex.soc.cores.liteeth_mini.mac import LiteEthMAC
from liteeth.phy import LiteEthPHY
from liteeth.core.mac import LiteEthMAC
class _CRG(Module):
def __init__(self, platform):

View file

@ -14,8 +14,8 @@ from litex.soc.cores.sdram.settings import PhySettings, IS42S16160
from litex.soc.cores.sdram.model import SDRAMPHYModel
from litex.soc.integration.soc_core import mem_decoder
from litex.soc.cores.liteeth_mini.phy.model import LiteEthPHYModel
from litex.soc.cores.liteeth_mini.mac import LiteEthMAC
from liteeth.phy.model import LiteEthPHYModel
from liteeth.core.mac import LiteEthMAC
class BaseSoC(SoCSDRAM):
def __init__(self, **kwargs):

View file

@ -9,10 +9,8 @@ from litex.gen.genlib.io import CRG
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
# TODO: use liteeth
from litex.soc.cores.liteeth_mini.phy import LiteEthPHY
from litex.soc.cores.liteeth_mini.mac import LiteEthMAC
from liteeth.phy import LiteEthPHY
from liteeth.core.mac import LiteEthMAC
class BaseSoC(SoCCore):
def __init__(self, platform, **kwargs):

View file

@ -1,28 +0,0 @@
Unless otherwise noted, LiteEth is copyright (C) 2015 Florent Kermarrec.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Other authors retain ownership of their contributions. If a submission can
reasonably be considered independently copyrightable, it's yours and we
encourage you to claim it with appropriate copyright notices. This submission
then falls under the "otherwise noted" category. All submissions are strongly
encouraged to use the two-clause BSD license reproduced above.

View file

@ -1,58 +0,0 @@
__ _ __ ______ __ __ ____ _
/ / (_) /____ / __/ /_/ / / |/ (_)__ (_)
/ /__/ / __/ -_) _// __/ _ \/ /|_/ / / _ \/ /
/____/_/\__/\__/___/\__/_//_/_/ /_/_/_//_/_/
Copyright 2012-2015 / EnjoyDigital / M-Labs Ltd
A small footprint and configurable minimal Ethernet core
powered by Migen
[> Intro
---------
LiteEthMini is a subset of LiteEth (https://github.com/enjoy-digital/liteeth)
intended to be used with a CPU and a software stack.
[> Features
-----------
- Ethernet MAC with various various PHYs (GMII, MII, RGMII, Loopback)
- SRAM storage and wishbone interface
[> Possible improvements
-------------------------
- add DMA interface to MAC
- add SGMII PHY
- ... See below Support and consulting :)
If you want to support these features, please contact us at florent [AT]
enjoy-digital.fr. You can also contact our partner on the public mailing list
devel [AT] lists.m-labs.hk.
[> License
-----------
LiteEthMini is released under the very permissive two-clause BSD license. Under
the terms of this license, you are authorized to use LiteEthMini for closed-source
proprietary designs.
Even though we do not require you to do so, those things are awesome, so please
do them if possible:
- tell us that you are using LiteEthMini
- cite LiteEthMini in publications related to research it has helped
- send us feedback and suggestions for improvements
- send us bug reports when something goes wrong
- send us the modifications and improvements you have done to LiteEthMini.
[> Support and consulting
--------------------------
We love open-source hardware and like sharing our designs with others.
LiteEthMini is mainly developed and maintained by EnjoyDigital.
If you would like to know more about LiteEthMini or if you are already a happy
user and would like to extend it for your needs, EnjoyDigital can provide standard
commercial support as well as consulting services.
So feel free to contact us, we'd love to work with you! (and eventually shorten
the list of the possible improvements :)
[> Contact
E-mail: florent [AT] enjoy-digital.fr

View file

@ -1,38 +0,0 @@
from litex.gen import *
from litex.gen.genlib.record import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.stream import *
class Port:
def connect(self, port):
r = [
Record.connect(self.source, port.sink),
Record.connect(port.source, self.sink)
]
return r
eth_mtu = 1532
eth_min_len = 46
eth_interpacket_gap = 12
eth_preamble = 0xD555555555555555
buffer_depth = 2**log2_int(eth_mtu, need_pow2=False)
def eth_phy_description(dw):
payload_layout = [
("data", dw),
("last_be", dw//8),
("error", dw//8)
]
return EndpointDescription(payload_layout, packetized=True)
def eth_mac_description(dw):
payload_layout = mac_header.get_layout() + [
("data", dw),
("last_be", dw//8),
("error", dw//8)
]
return EndpointDescription(payload_layout, packetized=True)

View file

@ -1,25 +0,0 @@
from litex.gen import *
from litex.soc.interconnect.csr import *
from litex.soc.cores.liteeth_mini.common import *
from litex.soc.cores.liteeth_mini.mac.core import LiteEthMACCore
from litex.soc.cores.liteeth_mini.mac.frontend.wishbone import LiteEthMACWishboneInterface
class LiteEthMAC(Module, AutoCSR):
def __init__(self, phy, dw,
interface="wishbone",
endianness="big",
with_preamble_crc=True):
self.submodules.core = LiteEthMACCore(phy, dw, endianness, with_preamble_crc)
self.csrs = []
if interface == "wishbone":
self.submodules.interface = LiteEthMACWishboneInterface(dw, 2, 2)
self.comb += Port.connect(self.interface, self.core)
self.ev, self.bus = self.interface.sram.ev, self.interface.bus
self.csrs = self.interface.get_csrs() + self.core.get_csrs()
else:
raise NotImplementedError
def get_csrs(self):
return self.csrs

View file

@ -1,100 +0,0 @@
from litex.gen import *
from litex.soc.interconnect.csr import *
from litex.soc.cores.liteeth_mini.common import *
from litex.soc.cores.liteeth_mini.mac.core import gap, preamble, crc, padding, last_be
from litex.soc.cores.liteeth_mini.phy.mii import LiteEthPHYMII
class LiteEthMACCore(Module, AutoCSR):
def __init__(self, phy, dw, endianness="big",
with_preamble_crc=True,
with_padding=True):
if dw < phy.dw:
raise ValueError("Core data width({}) must be larger than PHY data width({})".format(dw, phy.dw))
rx_pipeline = [phy]
tx_pipeline = [phy]
# Interpacket gap
tx_gap_inserter = gap.LiteEthMACGap(phy.dw)
rx_gap_checker = gap.LiteEthMACGap(phy.dw, ack_on_gap=True)
self.submodules += ClockDomainsRenamer("eth_tx")(tx_gap_inserter)
self.submodules += ClockDomainsRenamer("eth_rx")(rx_gap_checker)
tx_pipeline += [tx_gap_inserter]
rx_pipeline += [rx_gap_checker]
# Preamble / CRC
if with_preamble_crc:
self._preamble_crc = CSRStatus(reset=1)
# Preamble insert/check
preamble_inserter = preamble.LiteEthMACPreambleInserter(phy.dw)
preamble_checker = preamble.LiteEthMACPreambleChecker(phy.dw)
self.submodules += ClockDomainsRenamer("eth_tx")(preamble_inserter)
self.submodules += ClockDomainsRenamer("eth_rx")(preamble_checker)
# CRC insert/check
crc32_inserter = crc.LiteEthMACCRC32Inserter(eth_phy_description(phy.dw))
crc32_checker = crc.LiteEthMACCRC32Checker(eth_phy_description(phy.dw))
self.submodules += ClockDomainsRenamer("eth_tx")(crc32_inserter)
self.submodules += ClockDomainsRenamer("eth_rx")(crc32_checker)
tx_pipeline += [preamble_inserter, crc32_inserter]
rx_pipeline += [preamble_checker, crc32_checker]
# Padding
if with_padding:
padding_inserter = padding.LiteEthMACPaddingInserter(phy.dw, 60)
padding_checker = padding.LiteEthMACPaddingChecker(phy.dw, 60)
self.submodules += ClockDomainsRenamer("eth_tx")(padding_inserter)
self.submodules += ClockDomainsRenamer("eth_rx")(padding_checker)
tx_pipeline += [padding_inserter]
rx_pipeline += [padding_checker]
# Delimiters
if dw != 8:
tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw)
rx_last_be = last_be.LiteEthMACRXLastBE(phy.dw)
self.submodules += ClockDomainsRenamer("eth_tx")(tx_last_be)
self.submodules += ClockDomainsRenamer("eth_rx")(rx_last_be)
tx_pipeline += [tx_last_be]
rx_pipeline += [rx_last_be]
# Converters
if dw != phy.dw:
reverse = endianness == "big"
tx_converter = Converter(eth_phy_description(dw),
eth_phy_description(phy.dw),
reverse=reverse)
rx_converter = Converter(eth_phy_description(phy.dw),
eth_phy_description(dw),
reverse=reverse)
self.submodules += ClockDomainsRenamer("eth_tx")(tx_converter)
self.submodules += ClockDomainsRenamer("eth_rx")(rx_converter)
tx_pipeline += [tx_converter]
rx_pipeline += [rx_converter]
# Cross Domain Crossing
if isinstance(phy, LiteEthPHYMII):
fifo_depth = 8
else:
fifo_depth = 64
tx_cdc = AsyncFIFO(eth_phy_description(dw), fifo_depth)
rx_cdc = AsyncFIFO(eth_phy_description(dw), fifo_depth)
self.submodules += ClockDomainsRenamer({"write": "sys", "read": "eth_tx"})(tx_cdc)
self.submodules += ClockDomainsRenamer({"write": "eth_rx", "read": "sys"})(rx_cdc)
tx_pipeline += [tx_cdc]
rx_pipeline += [rx_cdc]
tx_pipeline_r = list(reversed(tx_pipeline))
for s, d in zip(tx_pipeline_r, tx_pipeline_r[1:]):
self.comb += s.source.connect(d.sink)
for s, d in zip(rx_pipeline, rx_pipeline[1:]):
self.comb += s.source.connect(d.sink)
self.sink = tx_pipeline[-1].sink
self.source = rx_pipeline[-1].source

View file

@ -1,287 +0,0 @@
from collections import OrderedDict
from functools import reduce
from operator import xor
from litex.gen import *
from litex.gen.genlib.misc import chooser
from litex.soc.interconnect.stream import *
class LiteEthMACCRCEngine(Module):
"""Cyclic Redundancy Check Engine
Compute next CRC value from last CRC value and data input using
an optimized asynchronous LFSR.
Parameters
----------
data_width : int
Width of the data bus.
width : int
Width of the CRC.
polynom : int
Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
Attributes
----------
data : in
Data input.
last : in
last CRC value.
next :
next CRC value.
"""
def __init__(self, data_width, width, polynom):
self.data = Signal(data_width)
self.last = Signal(width)
self.next = Signal(width)
# # #
def _optimize_eq(l):
"""
Replace even numbers of XORs in the equation
with an equivalent XOR
"""
d = OrderedDict()
for e in l:
if e in d:
d[e] += 1
else:
d[e] = 1
r = []
for key, value in d.items():
if value%2 != 0:
r.append(key)
return r
# compute and optimize CRC's LFSR
curval = [[("state", i)] for i in range(width)]
for i in range(data_width):
feedback = curval.pop() + [("din", i)]
for j in range(width-1):
if (polynom & (1<<(j+1))):
curval[j] += feedback
curval[j] = _optimize_eq(curval[j])
curval.insert(0, feedback)
# implement logic
for i in range(width):
xors = []
for t, n in curval[i]:
if t == "state":
xors += [self.last[n]]
elif t == "din":
xors += [self.data[n]]
self.comb += self.next[i].eq(reduce(xor, xors))
@ResetInserter()
@CEInserter()
class LiteEthMACCRC32(Module):
"""IEEE 802.3 CRC
Implement an IEEE 802.3 CRC generator/checker.
Parameters
----------
data_width : int
Width of the data bus.
Attributes
----------
d : in
Data input.
value : out
CRC value (used for generator).
error : out
CRC error (used for checker).
"""
width = 32
polynom = 0x04C11DB7
init = 2**width-1
check = 0xC704DD7B
def __init__(self, data_width):
self.data = Signal(data_width)
self.value = Signal(self.width)
self.error = Signal()
# # #
self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom)
reg = Signal(self.width, reset=self.init)
self.sync += reg.eq(self.engine.next)
self.comb += [
self.engine.data.eq(self.data),
self.engine.last.eq(reg),
self.value.eq(~reg[::-1]),
self.error.eq(self.engine.next != self.check)
]
class LiteEthMACCRCInserter(Module):
"""CRC Inserter
Append a CRC at the end of each packet.
Parameters
----------
description : description
description of the dataflow.
Attributes
----------
sink : in
Packets input without CRC.
source : out
Packets output with CRC.
"""
def __init__(self, crc_class, description):
self.sink = sink = Sink(description)
self.source = source = Source(description)
self.busy = Signal()
# # #
dw = len(sink.data)
crc = crc_class(dw)
fsm = FSM(reset_state="IDLE")
self.submodules += crc, fsm
fsm.act("IDLE",
crc.reset.eq(1),
sink.ack.eq(1),
If(sink.stb & sink.sop,
sink.ack.eq(0),
NextState("COPY"),
)
)
fsm.act("COPY",
crc.ce.eq(sink.stb & source.ack),
crc.data.eq(sink.data),
Record.connect(sink, source),
source.eop.eq(0),
If(sink.stb & sink.eop & source.ack,
NextState("INSERT"),
)
)
ratio = crc.width//dw
if ratio > 1:
cnt = Signal(max=ratio, reset=ratio-1)
cnt_done = Signal()
fsm.act("INSERT",
source.stb.eq(1),
chooser(crc.value, cnt, source.data, reverse=True),
If(cnt_done,
source.eop.eq(1),
If(source.ack, NextState("IDLE"))
)
)
self.comb += cnt_done.eq(cnt == 0)
self.sync += \
If(fsm.ongoing("IDLE"),
cnt.eq(cnt.reset)
).Elif(fsm.ongoing("INSERT") & ~cnt_done,
cnt.eq(cnt - source.ack)
)
else:
fsm.act("INSERT",
source.stb.eq(1),
source.eop.eq(1),
source.data.eq(crc.value),
If(source.ack, NextState("IDLE"))
)
self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
class LiteEthMACCRC32Inserter(LiteEthMACCRCInserter):
def __init__(self, description):
LiteEthMACCRCInserter.__init__(self, LiteEthMACCRC32, description)
class LiteEthMACCRCChecker(Module):
"""CRC Checker
Check CRC at the end of each packet.
Parameters
----------
description : description
description of the dataflow.
Attributes
----------
sink : in
Packets input with CRC.
source : out
Packets output without CRC and "error" set to 0
on eop when CRC OK / set to 1 when CRC KO.
"""
def __init__(self, crc_class, description):
self.sink = sink = Sink(description)
self.source = source = Source(description)
self.busy = Signal()
# # #
dw = len(sink.data)
crc = crc_class(dw)
self.submodules += crc
ratio = crc.width//dw
fifo = ResetInserter()(SyncFIFO(description, ratio + 1))
self.submodules += fifo
fsm = FSM(reset_state="RESET")
self.submodules += fsm
fifo_in = Signal()
fifo_out = Signal()
fifo_full = Signal()
self.comb += [
fifo_full.eq(fifo.fifo.level == ratio),
fifo_in.eq(sink.stb & (~fifo_full | fifo_out)),
fifo_out.eq(source.stb & source.ack),
Record.connect(sink, fifo.sink),
fifo.sink.stb.eq(fifo_in),
self.sink.ack.eq(fifo_in),
source.stb.eq(sink.stb & fifo_full),
source.sop.eq(fifo.source.sop),
source.eop.eq(sink.eop),
fifo.source.ack.eq(fifo_out),
source.payload.eq(fifo.source.payload),
source.error.eq(sink.error | crc.error),
]
fsm.act("RESET",
crc.reset.eq(1),
fifo.reset.eq(1),
NextState("IDLE"),
)
self.comb += crc.data.eq(sink.data)
fsm.act("IDLE",
If(sink.stb & sink.sop & sink.ack,
crc.ce.eq(1),
NextState("COPY")
)
)
fsm.act("COPY",
If(sink.stb & sink.ack,
crc.ce.eq(1),
If(sink.eop,
NextState("RESET")
)
)
)
self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
class LiteEthMACCRC32Checker(LiteEthMACCRCChecker):
def __init__(self, description):
LiteEthMACCRCChecker.__init__(self, LiteEthMACCRC32, description)

View file

@ -1,42 +0,0 @@
import math
from litex.gen import *
from litex.gen.genlib.fsm import *
from litex.soc.interconnect.stream import Sink, Source
from litex.soc.cores.liteeth_mini.common import eth_phy_description, eth_interpacket_gap
class LiteEthMACGap(Module):
def __init__(self, dw, ack_on_gap=False):
self.sink = sink = Sink(eth_phy_description(dw))
self.source = source = Source(eth_phy_description(dw))
# # #
gap = math.ceil(eth_interpacket_gap/(dw//8))
counter = Signal(max=gap)
counter_reset = Signal()
counter_ce = Signal()
self.sync += \
If(counter_reset,
counter.eq(0)
).Elif(counter_ce,
counter.eq(counter + 1)
)
self.submodules.fsm = fsm = FSM(reset_state="COPY")
fsm.act("COPY",
counter_reset.eq(1),
Record.connect(sink, source),
If(sink.stb & sink.eop & sink.ack,
NextState("GAP")
)
)
fsm.act("GAP",
counter_ce.eq(1),
sink.ack.eq(int(ack_on_gap)),
If(counter == (gap-1),
NextState("COPY")
)
)

View file

@ -1,46 +0,0 @@
from litex.gen import *
from litex.soc.interconnect.stream import *
from litex.soc.cores.liteeth_mini.common import eth_phy_description
class LiteEthMACTXLastBE(Module):
def __init__(self, dw):
self.sink = sink = Sink(eth_phy_description(dw))
self.source = source = Source(eth_phy_description(dw))
# # #
ongoing = Signal()
self.sync += \
If(sink.stb & sink.ack,
If(sink.sop,
ongoing.eq(1)
).Elif(sink.last_be,
ongoing.eq(0)
)
)
self.comb += [
source.stb.eq(sink.stb & (sink.sop | ongoing)),
source.sop.eq(sink.sop),
source.eop.eq(sink.last_be),
source.data.eq(sink.data),
sink.ack.eq(source.ack)
]
class LiteEthMACRXLastBE(Module):
def __init__(self, dw):
self.sink = sink = Sink(eth_phy_description(dw))
self.source = source = Source(eth_phy_description(dw))
# # #
self.comb += [
source.stb.eq(sink.stb),
source.sop.eq(sink.sop),
source.eop.eq(sink.eop),
source.data.eq(sink.data),
source.last_be.eq(sink.eop),
sink.ack.eq(source.ack)
]

View file

@ -1,68 +0,0 @@
import math
from litex.gen import *
from litex.soc.interconnect.stream import *
from litex.soc.cores.liteeth_mini.common import eth_phy_description
class LiteEthMACPaddingInserter(Module):
def __init__(self, dw, padding):
self.sink = sink = Sink(eth_phy_description(dw))
self.source = source = Source(eth_phy_description(dw))
# # #
padding_limit = math.ceil(padding/(dw/8))-1
counter = Signal(16, reset=1)
counter_done = Signal()
counter_reset = Signal()
counter_ce = Signal()
self.sync += If(counter_reset,
counter.eq(1)
).Elif(counter_ce,
counter.eq(counter + 1)
)
self.comb += [
counter_reset.eq(sink.stb & sink.sop & sink.ack),
counter_ce.eq(source.stb & source.ack),
counter_done.eq(counter >= padding_limit),
]
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
Record.connect(sink, source),
If(source.stb & source.ack,
counter_ce.eq(1),
If(sink.eop,
If(~counter_done,
source.eop.eq(0),
NextState("PADDING")
)
)
)
)
fsm.act("PADDING",
source.stb.eq(1),
source.eop.eq(counter_done),
source.data.eq(0),
If(source.ack,
If(counter_done,
NextState("IDLE")
)
)
)
class LiteEthMACPaddingChecker(Module):
def __init__(self, dw, packet_min_length):
self.sink = sink = Sink(eth_phy_description(dw))
self.source = source = Source(eth_phy_description(dw))
# # #
# TODO: see if we should drop the packet when
# payload size < minimum ethernet payload size
self.comb += Record.connect(sink, source)

View file

@ -1,156 +0,0 @@
from litex.gen import *
from litex.gen.genlib.fsm import *
from litex.gen.genlib.misc import chooser
from litex.gen.genlib.record import Record
from litex.soc.interconnect.stream import *
from litex.soc.cores.liteeth_mini.common import eth_phy_description, eth_preamble
class LiteEthMACPreambleInserter(Module):
def __init__(self, dw):
self.sink = Sink(eth_phy_description(dw))
self.source = Source(eth_phy_description(dw))
# # #
preamble = Signal(64, reset=eth_preamble)
cnt_max = (64//dw)-1
cnt = Signal(max=cnt_max+1)
clr_cnt = Signal()
inc_cnt = Signal()
self.sync += \
If(clr_cnt,
cnt.eq(0)
).Elif(inc_cnt,
cnt.eq(cnt+1)
)
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("IDLE",
self.sink.ack.eq(1),
clr_cnt.eq(1),
If(self.sink.stb & self.sink.sop,
self.sink.ack.eq(0),
NextState("INSERT"),
)
)
fsm.act("INSERT",
self.source.stb.eq(1),
self.source.sop.eq(cnt == 0),
chooser(preamble, cnt, self.source.data),
If(cnt == cnt_max,
If(self.source.ack, NextState("COPY"))
).Else(
inc_cnt.eq(self.source.ack)
)
)
self.comb += [
self.source.data.eq(self.sink.data),
self.source.last_be.eq(self.sink.last_be)
]
fsm.act("COPY",
Record.connect(self.sink, self.source, leave_out=set(["data", "last_be"])),
self.source.sop.eq(0),
If(self.sink.stb & self.sink.eop & self.source.ack,
NextState("IDLE"),
)
)
class LiteEthMACPreambleChecker(Module):
def __init__(self, dw):
self.sink = Sink(eth_phy_description(dw))
self.source = Source(eth_phy_description(dw))
# # #
preamble = Signal(64, reset=eth_preamble)
cnt_max = (64//dw) - 1
cnt = Signal(max=cnt_max+1)
clr_cnt = Signal()
inc_cnt = Signal()
self.sync += \
If(clr_cnt,
cnt.eq(0)
).Elif(inc_cnt,
cnt.eq(cnt+1)
)
discard = Signal()
clr_discard = Signal()
set_discard = Signal()
self.sync += \
If(clr_discard,
discard.eq(0)
).Elif(set_discard,
discard.eq(1)
)
sop = Signal()
clr_sop = Signal()
set_sop = Signal()
self.sync += \
If(clr_sop,
sop.eq(0)
).Elif(set_sop,
sop.eq(1)
)
ref = Signal(dw)
match = Signal()
self.comb += [
chooser(preamble, cnt, ref),
match.eq(self.sink.data == ref)
]
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("IDLE",
self.sink.ack.eq(1),
clr_cnt.eq(1),
clr_discard.eq(1),
If(self.sink.stb & self.sink.sop,
clr_cnt.eq(0),
inc_cnt.eq(1),
clr_discard.eq(0),
set_discard.eq(~match),
NextState("CHECK"),
)
)
fsm.act("CHECK",
self.sink.ack.eq(1),
If(self.sink.stb,
set_discard.eq(~match),
If(cnt == cnt_max,
If(discard | (~match),
NextState("IDLE")
).Else(
set_sop.eq(1),
NextState("COPY")
)
).Else(
inc_cnt.eq(1)
)
)
)
self.comb += [
self.source.data.eq(self.sink.data),
self.source.last_be.eq(self.sink.last_be)
]
fsm.act("COPY",
Record.connect(self.sink, self.source, leave_out=set(["data", "last_be"])),
self.source.sop.eq(sop),
clr_sop.eq(self.source.stb & self.source.ack),
If(self.source.stb & self.source.eop & self.source.ack,
NextState("IDLE"),
)
)

View file

@ -1,252 +0,0 @@
from litex.soc import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.csr_eventmanager import *
from litex.soc.interconnect.stream import *
from litex.soc.cores.liteeth_mini.common import eth_phy_description
class LiteEthMACSRAMWriter(Module, AutoCSR):
def __init__(self, dw, depth, nslots=2):
self.sink = sink = Sink(eth_phy_description(dw))
self.crc_error = Signal()
slotbits = max(log2_int(nslots), 1)
lengthbits = log2_int(depth*4) # length in bytes
self._slot = CSRStatus(slotbits)
self._length = CSRStatus(lengthbits)
self.submodules.ev = EventManager()
self.ev.available = EventSourceLevel()
self.ev.finalize()
# # #
# packet dropped if no slot available
sink.ack.reset = 1
# length computation
increment = Signal(3)
self.comb += \
If(sink.last_be[3],
increment.eq(1)
).Elif(sink.last_be[2],
increment.eq(2)
).Elif(sink.last_be[1],
increment.eq(3)
).Else(
increment.eq(4)
)
counter = Signal(lengthbits)
counter_reset = Signal()
counter_ce = Signal()
self.sync += If(counter_reset,
counter.eq(0)
).Elif(counter_ce,
counter.eq(counter + increment)
)
# slot computation
slot = Signal(slotbits)
slot_ce = Signal()
self.sync += If(slot_ce, slot.eq(slot + 1))
ongoing = Signal()
# status fifo
fifo = SyncFIFO([("slot", slotbits), ("length", lengthbits)], nslots)
self.submodules += fifo
# fsm
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("IDLE",
If(sink.stb & sink.sop,
If(fifo.sink.ack,
ongoing.eq(1),
counter_ce.eq(1),
NextState("WRITE")
)
)
)
fsm.act("WRITE",
counter_ce.eq(sink.stb),
ongoing.eq(1),
If(sink.stb & sink.eop,
If((sink.error & sink.last_be) != 0,
NextState("DISCARD")
).Else(
NextState("TERMINATE")
)
)
)
fsm.act("DISCARD",
counter_reset.eq(1),
NextState("IDLE")
)
self.comb += [
fifo.sink.slot.eq(slot),
fifo.sink.length.eq(counter)
]
fsm.act("TERMINATE",
counter_reset.eq(1),
slot_ce.eq(1),
fifo.sink.stb.eq(1),
NextState("IDLE")
)
self.comb += [
fifo.source.ack.eq(self.ev.available.clear),
self.ev.available.trigger.eq(fifo.source.stb),
self._slot.status.eq(fifo.source.slot),
self._length.status.eq(fifo.source.length),
]
# memory
mems = [None]*nslots
ports = [None]*nslots
for n in range(nslots):
mems[n] = Memory(dw, depth)
ports[n] = mems[n].get_port(write_capable=True)
self.specials += ports[n]
self.mems = mems
cases = {}
for n, port in enumerate(ports):
cases[n] = [
ports[n].adr.eq(counter[2:]),
ports[n].dat_w.eq(sink.data),
If(sink.stb & ongoing,
ports[n].we.eq(0xf)
)
]
self.comb += Case(slot, cases)
class LiteEthMACSRAMReader(Module, AutoCSR):
def __init__(self, dw, depth, nslots=2):
self.source = source = Source(eth_phy_description(dw))
slotbits = max(log2_int(nslots), 1)
lengthbits = log2_int(depth*4) # length in bytes
self.lengthbits = lengthbits
self._start = CSR()
self._ready = CSRStatus()
self._slot = CSRStorage(slotbits)
self._length = CSRStorage(lengthbits)
self.submodules.ev = EventManager()
self.ev.done = EventSourcePulse()
self.ev.finalize()
# # #
# command fifo
fifo = SyncFIFO([("slot", slotbits), ("length", lengthbits)], nslots)
self.submodules += fifo
self.comb += [
fifo.sink.stb.eq(self._start.re),
fifo.sink.slot.eq(self._slot.storage),
fifo.sink.length.eq(self._length.storage),
self._ready.status.eq(fifo.sink.ack)
]
# length computation
counter = Signal(lengthbits)
counter_reset = Signal()
counter_ce = Signal()
self.sync += If(counter_reset,
counter.eq(0)
).Elif(counter_ce,
counter.eq(counter + 4)
)
# fsm
first = Signal()
last = Signal()
last_d = Signal()
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("IDLE",
counter_reset.eq(1),
If(fifo.source.stb,
NextState("CHECK")
)
)
fsm.act("CHECK",
If(~last_d,
NextState("SEND"),
).Else(
NextState("END"),
)
)
length_lsb = fifo.source.length[0:2]
self.comb += [
If(last,
If(length_lsb == 3,
source.last_be.eq(0b0010)
).Elif(length_lsb == 2,
source.last_be.eq(0b0100)
).Elif(length_lsb == 1,
source.last_be.eq(0b1000)
).Else(
source.last_be.eq(0b0001)
)
)
]
fsm.act("SEND",
source.stb.eq(1),
source.sop.eq(first),
source.eop.eq(last),
If(source.ack,
counter_ce.eq(~last),
NextState("CHECK")
)
)
fsm.act("END",
fifo.source.ack.eq(1),
self.ev.done.trigger.eq(1),
NextState("IDLE")
)
# first/last computation
self.sync += [
If(fsm.ongoing("IDLE"),
first.eq(1)
).Elif(source.stb & source.ack,
first.eq(0)
)
]
self.comb += last.eq((counter + 4) >= fifo.source.length)
self.sync += last_d.eq(last)
# memory
rd_slot = fifo.source.slot
mems = [None]*nslots
ports = [None]*nslots
for n in range(nslots):
mems[n] = Memory(dw, depth)
ports[n] = mems[n].get_port()
self.specials += ports[n]
self.mems = mems
cases = {}
for n, port in enumerate(ports):
self.comb += ports[n].adr.eq(counter[2:])
cases[n] = [source.data.eq(port.dat_r)]
self.comb += Case(rd_slot, cases)
class LiteEthMACSRAM(Module, AutoCSR):
def __init__(self, dw, depth, nrxslots, ntxslots):
self.submodules.writer = LiteEthMACSRAMWriter(dw, depth, nrxslots)
self.submodules.reader = LiteEthMACSRAMReader(dw, depth, ntxslots)
self.submodules.ev = SharedIRQ(self.writer.ev, self.reader.ev)
self.sink, self.source = self.writer.sink, self.reader.source

View file

@ -1,44 +0,0 @@
from litex.gen import *
from litex.gen.fhdl.simplify import FullMemoryWE
from litex.soc.interconnect import wishbone
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.stream import *
from litex.soc.cores.liteeth_mini.common import eth_phy_description, buffer_depth
from litex.soc.cores.liteeth_mini.mac.frontend import sram
class LiteEthMACWishboneInterface(Module, AutoCSR):
def __init__(self, dw, nrxslots=2, ntxslots=2):
self.sink = Sink(eth_phy_description(dw))
self.source = Source(eth_phy_description(dw))
self.bus = wishbone.Interface()
# # #
# storage in SRAM
sram_depth = buffer_depth//(dw//8)
self.submodules.sram = sram.LiteEthMACSRAM(dw, sram_depth, nrxslots, ntxslots)
self.comb += [
Record.connect(self.sink, self.sram.sink),
Record.connect(self.sram.source, self.source)
]
# Wishbone interface
wb_rx_sram_ifs = [wishbone.SRAM(self.sram.writer.mems[n], read_only=True)
for n in range(nrxslots)]
# TODO: FullMemoryWE should move to Mibuild
wb_tx_sram_ifs = [FullMemoryWE()(wishbone.SRAM(self.sram.reader.mems[n], read_only=False))
for n in range(ntxslots)]
wb_sram_ifs = wb_rx_sram_ifs + wb_tx_sram_ifs
wb_slaves = []
decoderoffset = log2_int(sram_depth)
decoderbits = log2_int(len(wb_sram_ifs))
for n, wb_sram_if in enumerate(wb_sram_ifs):
def slave_filter(a, v=n):
return a[decoderoffset:decoderoffset+decoderbits] == v
wb_slaves.append((slave_filter, wb_sram_if.bus))
self.submodules += wb_sram_if
wb_con = wishbone.Decoder(self.bus, wb_slaves, register=True)
self.submodules += wb_con

View file

@ -1,23 +0,0 @@
from litex.soc.cores.liteeth_mini.common import *
def LiteEthPHY(clock_pads, pads, clk_freq=None, **kwargs):
# Autodetect PHY
if hasattr(clock_pads, "gtx") and len(pads.tx_data) == 8:
if hasattr(clock_pads, "tx"):
# This is a 10/100/1G PHY
from litex.soc.cores.liteeth_mini.phy.gmii_mii import LiteEthPHYGMIIMII
return LiteEthPHYGMIIMII(clock_pads, pads, clk_freq=clk_freq, **kwargs)
else:
# This is a pure 1G PHY
from litex.soc.cores.liteeth_mini.phy.gmii import LiteEthPHYGMII
return LiteEthPHYGMII(clock_pads, pads, **kwargs)
elif hasattr(pads, "rx_ctl"):
# This is a 10/100/1G RGMII PHY
raise ValueError("RGMII PHYs are specific to vendors (for now), use direct instantiation")
elif len(pads.tx_data) == 4:
# This is a MII PHY
from litex.soc.cores.liteeth_mini.phy.mii import LiteEthPHYMII
return LiteEthPHYMII(clock_pads, pads, **kwargs)
else:
raise ValueError("Unable to autodetect PHY from platform file, use direct instantiation")

View file

@ -1,98 +0,0 @@
from litex.gen import *
from litex.gen.genlib.io import DDROutput
from litex.gen.genlib.resetsync import AsyncResetSynchronizer
from litex.soc.cores.liteeth_mini.common import *
class LiteEthPHYGMIITX(Module):
def __init__(self, pads, pads_register=True):
self.sink = sink = Sink(eth_phy_description(8))
# # #
if hasattr(pads, "tx_er"):
self.sync += pads.tx_er.eq(0)
pads_eq = [
pads.tx_en.eq(sink.stb),
pads.tx_data.eq(sink.data)
]
if pads_register:
self.sync += pads_eq
else:
self.comb += pads_eq
self.comb += sink.ack.eq(1)
class LiteEthPHYGMIIRX(Module):
def __init__(self, pads):
self.source = source = Source(eth_phy_description(8))
# # #
dv_d = Signal()
self.sync += dv_d.eq(pads.dv)
sop = Signal()
eop = Signal()
self.comb += [
sop.eq(pads.dv & ~dv_d),
eop.eq(~pads.dv & dv_d)
]
self.sync += [
source.stb.eq(pads.dv),
source.sop.eq(sop),
source.data.eq(pads.rx_data)
]
self.comb += source.eop.eq(eop)
class LiteEthPHYGMIICRG(Module, AutoCSR):
def __init__(self, clock_pads, pads, with_hw_init_reset, mii_mode=0):
self._reset = CSRStorage()
# # #
self.clock_domains.cd_eth_rx = ClockDomain()
self.clock_domains.cd_eth_tx = ClockDomain()
# RX : Let the synthesis tool insert the appropriate clock buffer
self.comb += self.cd_eth_rx.clk.eq(clock_pads.rx)
# TX : GMII: Drive clock_pads.gtx, clock_pads.tx unused
# MII: Use PHY clock_pads.tx as eth_tx_clk, do not drive clock_pads.gtx
self.specials += DDROutput(1, mii_mode, clock_pads.gtx, ClockSignal("eth_tx"))
# XXX Xilinx specific, replace BUFGMUX with a generic clock buffer?
self.specials += Instance("BUFGMUX",
i_I0=self.cd_eth_rx.clk,
i_I1=clock_pads.tx,
i_S=mii_mode,
o_O=self.cd_eth_tx.clk)
if with_hw_init_reset:
reset = Signal()
counter = Signal(max=512)
counter_done = Signal()
counter_ce = Signal()
self.sync += If(counter_ce, counter.eq(counter + 1))
self.comb += [
counter_done.eq(counter == 256),
counter_ce.eq(~counter_done),
reset.eq(~counter_done | self._reset.storage)
]
else:
reset = self._reset.storage
self.comb += pads.rst_n.eq(~reset)
self.specials += [
AsyncResetSynchronizer(self.cd_eth_tx, reset),
AsyncResetSynchronizer(self.cd_eth_rx, reset),
]
class LiteEthPHYGMII(Module, AutoCSR):
def __init__(self, clock_pads, pads, with_hw_init_reset=True):
self.dw = 8
self.submodules.crg = LiteEthPHYGMIICRG(clock_pads, pads, with_hw_init_reset)
self.submodules.tx = ClockDomainsRenamer("eth_tx")(LiteEthPHYGMIITX(pads))
self.submodules.rx = ClockDomainsRenamer("eth_rx")(LiteEthPHYGMIIRX(pads))
self.sink, self.source = self.tx.sink, self.rx.source

View file

@ -1,170 +0,0 @@
from litex.gen import *
from litex.gen.genlib.io import DDROutput
from litex.gen.genlib.cdc import PulseSynchronizer
from litex.soc.interconnect.stream import *
from litex.soc.cores.liteeth_mini.common import *
from litex.soc.cores.liteeth_mini.phy.gmii import LiteEthPHYGMIICRG
from litex.soc.cores.liteeth_mini.phy.mii import LiteEthPHYMIITX, LiteEthPHYMIIRX
from litex.soc.cores.liteeth_mini.phy.gmii import LiteEthPHYGMIITX, LiteEthPHYGMIIRX
modes = {
"GMII": 0,
"MII": 1
}
tx_pads_layout = [("tx_er", 1), ("tx_en", 1), ("tx_data", 8)]
rx_pads_layout = [("rx_er", 1), ("dv", 1), ("rx_data", 8)]
class LiteEthPHYGMIIMIITX(Module):
def __init__(self, pads, mode):
self.sink = sink = Sink(eth_phy_description(8))
# # #
gmii_tx_pads = Record(tx_pads_layout)
gmii_tx = LiteEthPHYGMIITX(gmii_tx_pads, pads_register=False)
self.submodules += gmii_tx
mii_tx_pads = Record(tx_pads_layout)
mii_tx = LiteEthPHYMIITX(mii_tx_pads, pads_register=False)
self.submodules += mii_tx
demux = Demultiplexer(eth_phy_description(8), 2)
self.submodules += demux
self.comb += [
demux.sel.eq(mode == modes["MII"]),
Record.connect(sink, demux.sink),
Record.connect(demux.source0, gmii_tx.sink),
Record.connect(demux.source1, mii_tx.sink),
]
if hasattr(pads, "tx_er"):
self.comb += pads.tx_er.eq(0)
self.sync += [
If(mode == modes["MII"],
pads.tx_en.eq(mii_tx_pads.tx_en),
pads.tx_data.eq(mii_tx_pads.tx_data),
).Else(
pads.tx_en.eq(gmii_tx_pads.tx_en),
pads.tx_data.eq(gmii_tx_pads.tx_data),
)
]
class LiteEthPHYGMIIMIIRX(Module):
def __init__(self, pads, mode):
self.source = source = Source(eth_phy_description(8))
# # #
pads_d = Record(rx_pads_layout)
self.sync += [
pads_d.dv.eq(pads.dv),
pads_d.rx_data.eq(pads.rx_data)
]
gmii_rx = LiteEthPHYGMIIRX(pads_d)
self.submodules += gmii_rx
mii_rx = LiteEthPHYMIIRX(pads_d)
self.submodules += mii_rx
mux = Multiplexer(eth_phy_description(8), 2)
self.submodules += mux
self.comb += [
mux.sel.eq(mode == modes["MII"]),
Record.connect(gmii_rx.source, mux.sink0),
Record.connect(mii_rx.source, mux.sink1),
Record.connect(mux.source, source)
]
class LiteEthGMIIMIIModeDetection(Module, AutoCSR):
def __init__(self, clk_freq):
self.mode = Signal()
self._mode = CSRStatus()
# # #
mode = Signal()
update_mode = Signal()
self.sync += \
If(update_mode,
self.mode.eq(mode)
)
self.comb += self._mode.status.eq(self.mode)
# Principle:
# sys_clk >= 125MHz
# eth_rx <= 125Mhz
# We generate ticks every 1024 clock cycles in eth_rx domain
# and measure ticks period in sys_clk domain.
# Generate a tick every 1024 clock cycles (eth_rx clock domain)
eth_tick = Signal()
eth_counter = Signal(10)
self.sync.eth_rx += eth_counter.eq(eth_counter + 1)
self.comb += eth_tick.eq(eth_counter == 0)
# Synchronize tick (sys clock domain)
sys_tick = Signal()
eth_ps = PulseSynchronizer("eth_rx", "sys")
self.comb += [
eth_ps.i.eq(eth_tick),
sys_tick.eq(eth_ps.o)
]
self.submodules += eth_ps
# sys_clk domain counter
sys_counter = Signal(24)
sys_counter_reset = Signal()
sys_counter_ce = Signal()
self.sync += [
If(sys_counter_reset,
sys_counter.eq(0)
).Elif(sys_counter_ce,
sys_counter.eq(sys_counter + 1)
)
]
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("IDLE",
sys_counter_reset.eq(1),
If(sys_tick,
NextState("COUNT")
)
)
fsm.act("COUNT",
sys_counter_ce.eq(1),
If(sys_tick,
NextState("DETECTION")
)
)
fsm.act("DETECTION",
update_mode.eq(1),
# if freq < 125MHz-5% use MII mode
If(sys_counter > int((clk_freq/125000000)*1024*1.05),
mode.eq(1)
# if freq >= 125MHz-5% use GMII mode
).Else(
mode.eq(0)
),
NextState("IDLE")
)
class LiteEthPHYGMIIMII(Module, AutoCSR):
def __init__(self, clock_pads, pads, clk_freq, with_hw_init_reset=True):
self.dw = 8
# Note: we can use GMII CRG since it also handles tx clock pad used for MII
self.submodules.mode_detection = LiteEthGMIIMIIModeDetection(clk_freq)
mode = self.mode_detection.mode
self.submodules.crg = LiteEthPHYGMIICRG(clock_pads, pads, with_hw_init_reset, mode == modes["MII"])
self.submodules.tx = ClockDomainsRenamer("eth_tx")(LiteEthPHYGMIIMIITX(pads, mode))
self.submodules.rx = ClockDomainsRenamer("eth_rx")(LiteEthPHYGMIIMIIRX(pads, mode))
self.sink, self.source = self.tx.sink, self.rx.source

View file

@ -1,35 +0,0 @@
from litex.gen import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.stream import *
from litex.soc.cores.liteeth_mini.common import *
from litex.soc.cores.liteeth.mini.generic import *
class LiteEthPHYLoopbackCRG(Module, AutoCSR):
def __init__(self):
self._reset = CSRStorage()
# # #
self.clock_domains.cd_eth_rx = ClockDomain()
self.clock_domains.cd_eth_tx = ClockDomain()
self.comb += [
self.cd_eth_rx.clk.eq(ClockSignal()),
self.cd_eth_tx.clk.eq(ClockSignal())
]
reset = self._reset.storage
self.comb += [
self.cd_eth_rx.rst.eq(reset),
self.cd_eth_tx.rst.eq(reset)
]
class LiteEthPHYLoopback(Module, AutoCSR):
def __init__(self):
self.dw = 8
self.submodules.crg = LiteEthLoopbackPHYCRG()
self.sink = Sink(eth_phy_description(8))
self.source = Source(eth_phy_description(8))
self.comb += Record.connect(self.sink, self.source)

View file

@ -1,110 +0,0 @@
from litex.gen import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.stream import *
from litex.soc.cores.liteeth_mini.common import *
def converter_description(dw):
payload_layout = [("data", dw)]
return EndpointDescription(payload_layout, packetized=True)
class LiteEthPHYMIITX(Module):
def __init__(self, pads, pads_register=True):
self.sink = sink = Sink(eth_phy_description(8))
# # #
if hasattr(pads, "tx_er"):
self.sync += pads.tx_er.eq(0)
converter = Converter(converter_description(8),
converter_description(4))
self.submodules += converter
self.comb += [
converter.sink.stb.eq(sink.stb),
converter.sink.data.eq(sink.data),
sink.ack.eq(converter.sink.ack),
converter.source.ack.eq(1)
]
pads_eq = [
pads.tx_en.eq(converter.source.stb),
pads.tx_data.eq(converter.source.data)
]
if pads_register:
self.sync += pads_eq
else:
self.comb += pads_eq
class LiteEthPHYMIIRX(Module):
def __init__(self, pads):
self.source = source = Source(eth_phy_description(8))
# # #
sop = Signal(reset=1)
sop_set = Signal()
sop_clr = Signal()
self.sync += If(sop_set, sop.eq(1)).Elif(sop_clr, sop.eq(0))
converter = Converter(converter_description(4),
converter_description(8))
converter = ResetInserter()(converter)
self.submodules += converter
self.sync += [
converter.reset.eq(~pads.dv),
converter.sink.stb.eq(1),
converter.sink.data.eq(pads.rx_data)
]
self.sync += [
sop_set.eq(~pads.dv),
sop_clr.eq(pads.dv)
]
self.comb += [
converter.sink.sop.eq(sop),
converter.sink.eop.eq(~pads.dv)
]
self.comb += Record.connect(converter.source, source)
class LiteEthPHYMIICRG(Module, AutoCSR):
def __init__(self, clock_pads, pads, with_hw_init_reset):
self._reset = CSRStorage()
# # #
if hasattr(clock_pads, "phy"):
self.sync.base50 += clock_pads.phy.eq(~clock_pads.phy)
self.clock_domains.cd_eth_rx = ClockDomain()
self.clock_domains.cd_eth_tx = ClockDomain()
self.comb += self.cd_eth_rx.clk.eq(clock_pads.rx)
self.comb += self.cd_eth_tx.clk.eq(clock_pads.tx)
if with_hw_init_reset:
reset = Signal()
counter_done = Signal()
self.submodules.counter = counter = Counter(max=512)
self.comb += [
counter_done.eq(counter.value == 256),
counter.ce.eq(~counter_done),
reset.eq(~counter_done | self._reset.storage)
]
else:
reset = self._reset.storage
self.comb += pads.rst_n.eq(~reset)
self.specials += [
AsyncResetSynchronizer(self.cd_eth_tx, reset),
AsyncResetSynchronizer(self.cd_eth_rx, reset),
]
class LiteEthPHYMII(Module, AutoCSR):
def __init__(self, clock_pads, pads, with_hw_init_reset=True):
self.dw = 8
self.submodules.crg = LiteEthPHYMIICRG(clock_pads, pads, with_hw_init_reset)
self.submodules.tx = ClockDomainsRenamer("eth_tx")(LiteEthPHYMIITX(pads))
self.submodules.rx = ClockDomainsRenamer("eth_tx")(LiteEthPHYMIIRX(pads))
self.sink, self.source = self.tx.sink, self.rx.source

View file

@ -1,58 +0,0 @@
import os
from litex.soc.cores.liteeth_mini.common import *
class LiteEthPHYModelCRG(Module, AutoCSR):
def __init__(self):
self._reset = CSRStorage()
# # #
self.clock_domains.cd_eth_rx = ClockDomain()
self.clock_domains.cd_eth_tx = ClockDomain()
self.comb += [
self.cd_eth_rx.clk.eq(ClockSignal()),
self.cd_eth_tx.clk.eq(ClockSignal())
]
reset = self._reset.storage
self.comb += [
self.cd_eth_rx.rst.eq(reset),
self.cd_eth_tx.rst.eq(reset)
]
class LiteEthPHYModel(Module, AutoCSR):
def __init__(self, pads, tap="tap0", ip_address="192.168.0.14"):
self.dw = 8
self.submodules.crg = LiteEthPHYModelCRG()
self.sink = sink = Sink(eth_phy_description(8))
self.source = source = Source(eth_phy_description(8))
self.tap = tap
self.ip_address = ip_address
self.comb += [
pads.source_stb.eq(self.sink.stb),
pads.source_data.eq(self.sink.data),
self.sink.ack.eq(1)
]
self.sync += [
self.source.stb.eq(pads.sink_stb),
self.source.sop.eq(pads.sink_stb & ~self.source.stb),
self.source.data.eq(pads.sink_data),
]
self.comb += [
self.source.eop.eq(~pads.sink_stb & self.source.stb),
]
# TODO avoid use of os.system
os.system("openvpn --mktun --dev {}".format(self.tap))
os.system("ifconfig {} {} up".format(self.tap, self.ip_address))
os.system("mknod /dev/net/{} c 10 200".format(self.tap))
def do_exit(self, *args, **kwargs):
# TODO avoid use of os.system
os.system("rm -f /dev/net/{}".format(self.tap))
os.system("openvpn --rmtun --dev {}".format(self.tap))

View file

@ -1,161 +0,0 @@
# RGMII PHY for Spartan-6
from litex.gen import *
from litex.gen.genlib.io import DDROutput
from litex.gen.genlib.misc import WaitTimer
from litex.gen.genlib.fsm import FSM, NextState
from litex.soc.interconnect.stream import *
from litex.soc.interconnect.csr import *
from litex.soc.cores.liteeth_mini.common import *
class LiteEthPHYRGMIITX(Module):
def __init__(self, pads, pads_register=True):
self.sink = sink = Sink(eth_phy_description(8))
# # #
self.specials += Instance("ODDR2",
p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="ASYNC",
i_C0=ClockSignal("eth_tx"), i_C1=~ClockSignal("eth_tx"),
i_CE=1, i_S=0, i_R=0,
i_D0=sink.stb, i_D1=sink.stb, o_Q=pads.tx_ctl,
)
for i in range(4):
self.specials += Instance("ODDR2",
p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="ASYNC",
i_C0=ClockSignal("eth_tx"), i_C1=~ClockSignal("eth_tx"),
i_CE=1, i_S=0, i_R=0,
i_D0=sink.data[i], i_D1=sink.data[4+i], o_Q=pads.tx_data[i],
)
self.comb += sink.ack.eq(1)
class LiteEthPHYRGMIIRX(Module):
def __init__(self, pads):
self.source = source = Source(eth_phy_description(8))
# # #
rx_ctl = Signal()
rx_data = Signal(8)
self.specials += Instance("IDDR2",
p_DDR_ALIGNMENT="C0", p_INIT_Q0=0, p_INIT_Q1=0, p_SRTYPE="ASYNC",
i_C0=ClockSignal("eth_rx"), i_C1=~ClockSignal("eth_rx"),
i_CE=1, i_S=0, i_R=0,
i_D=pads.rx_ctl, o_Q1=rx_ctl,
)
for i in range(4):
self.specials += Instance("IDDR2",
p_DDR_ALIGNMENT="C0", p_INIT_Q0=0, p_INIT_Q1=0, p_SRTYPE="ASYNC",
i_C0=ClockSignal("eth_rx"), i_C1=~ClockSignal("eth_rx"),
i_CE=1, i_S=0, i_R=0,
i_D=pads.rx_data[i], o_Q0=rx_data[4+i], o_Q1=rx_data[i],
)
rx_ctl_d = Signal()
self.sync += rx_ctl_d.eq(rx_ctl)
sop = Signal()
eop = Signal()
self.comb += [
sop.eq(rx_ctl & ~rx_ctl_d),
eop.eq(~rx_ctl & rx_ctl_d)
]
self.sync += [
source.stb.eq(rx_ctl),
source.sop.eq(sop),
source.data.eq(rx_data)
]
self.comb += source.eop.eq(eop)
class LiteEthPHYRGMIICRG(Module, AutoCSR):
def __init__(self, clock_pads, pads, with_hw_init_reset):
self._reset = CSRStorage()
# # #
self.clock_domains.cd_eth_rx = ClockDomain()
self.clock_domains.cd_eth_tx = ClockDomain()
# RX
dcm_reset = Signal()
dcm_locked = Signal()
timer = WaitTimer(1024)
fsm = FSM(reset_state="DCM_RESET")
self.submodules += timer, fsm
fsm.act("DCM_RESET",
dcm_reset.eq(1),
timer.wait.eq(1),
If(timer.done,
timer.wait.eq(0),
NextState("DCM_WAIT")
)
)
fsm.act("DCM_WAIT",
timer.wait.eq(1),
If(timer.done,
NextState("DCM_CHECK_LOCK")
)
)
fsm.act("DCM_CHECK_LOCK",
If(~dcm_locked,
NextState("DCM_RESET")
)
)
clk90_rx = Signal()
clk0_rx = Signal()
clk0_rx_bufg = Signal()
self.specials += Instance("DCM",
i_CLKIN=clock_pads.rx,
i_CLKFB=clk0_rx_bufg,
o_CLK0=clk0_rx,
o_CLK90=clk90_rx,
o_LOCKED=dcm_locked,
i_PSEN=0,
i_PSCLK=0,
i_PSINCDEC=0,
i_RST=dcm_reset
)
self.specials += Instance("BUFG", i_I=clk0_rx, o_O=clk0_rx_bufg)
self.specials += Instance("BUFG", i_I=clk90_rx, o_O=self.cd_eth_rx.clk)
# TX
self.specials += DDROutput(1, 0, clock_pads.tx, ClockSignal("eth_tx"))
self.specials += Instance("BUFG", i_I=self.cd_eth_rx.clk, o_O=self.cd_eth_tx.clk)
# Reset
if with_hw_init_reset:
reset = Signal()
counter_done = Signal()
self.submodules.counter = counter = Counter(max=512)
self.comb += [
counter_done.eq(counter.value == 256),
counter.ce.eq(~counter_done),
reset.eq(~counter_done | self._reset.storage)
]
else:
reset = self._reset.storage
self.comb += pads.rst_n.eq(~reset)
self.specials += [
AsyncResetSynchronizer(self.cd_eth_tx, reset),
AsyncResetSynchronizer(self.cd_eth_rx, reset),
]
class LiteEthPHYRGMII(Module, AutoCSR):
def __init__(self, clock_pads, pads, with_hw_init_reset=True):
self.dw = 8
self.submodules.crg = LiteEthPHYRGMIICRG(clock_pads, pads, with_hw_init_reset)
self.submodules.tx = ClockDomainsRenamer("eth_tx")(LiteEthPHYRGMIITX(pads))
self.submodules.rx = ClockDomainsRenamer("eth_rx")(LiteEthPHYRGMIIRX(pads))
self.sink, self.source = self.tx.sink, self.rx.source