start code adaptation
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 27 Jan 2015 23:33:26 +0000 (00:33 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 27 Jan 2015 23:51:31 +0000 (00:51 +0100)
16 files changed:
liteethernet/common.py [new file with mode: 0644]
liteethernet/mac/__init__.py
liteethernet/mac/core/__init__.py
liteethernet/mac/core/crc.py [new file with mode: 0644]
liteethernet/mac/core/last_be.py
liteethernet/mac/core/preamble.py
liteethernet/mac/frontend/sram.py
liteethernet/mac/frontend/wishbone.py [new file with mode: 0644]
liteethernet/mac/phy/__init__.py [deleted file]
liteethernet/mac/phy/gmii.py [deleted file]
liteethernet/mac/phy/loopback.py [deleted file]
liteethernet/mac/phy/mii.py [deleted file]
liteethernet/phy/__init__.py [new file with mode: 0644]
liteethernet/phy/gmii.py [new file with mode: 0644]
liteethernet/phy/loopback.py [new file with mode: 0644]
liteethernet/phy/mii.py [new file with mode: 0644]

diff --git a/liteethernet/common.py b/liteethernet/common.py
new file mode 100644 (file)
index 0000000..177943e
--- /dev/null
@@ -0,0 +1,14 @@
+from migen.fhdl.std import *
+from migen.flow.actor import EndpointDescription
+
+eth_mtu = 1532
+eth_preamble = 0xD555555555555555
+buffer_depth = 2**log2_int(eth_mtu, need_pow2=False)
+
+def eth_description(dw):
+       layout = [
+               ("d", dw),
+               ("last_be", dw//8),
+               ("error", dw//8)
+       ]
+       return EndpointDescription(layout, packetized=True)
index a7ea0c2c2938fda07777a3fc9d19b330770253cf..e9b2ccfaa966905db8f1c1f2c3abc854d2f00228 100644 (file)
@@ -1,66 +1,9 @@
-# This file is Copyright (c) 2014 Florent Kermarrec <florent@enjoy-digital.fr>
-# License: BSD
+from liteethernet.common import *
+from liteethernet.mac import LiteEthernetMAC
 
-from migen.fhdl.std import *
-
-from migen.bus import wishbone
-from migen.actorlib.fifo import AsyncFIFO
-from migen.actorlib.structuring import Converter, Pipeline
-from migen.bank.eventmanager import SharedIRQ
-from migen.bank.description import *
-from migen.fhdl.simplify import *
-
-from misoclib.ethmac.common import *
-from misoclib.ethmac.preamble import PreambleInserter, PreambleChecker
-from migen.actorlib.crc import CRC32Inserter, CRC32Checker
-from misoclib.ethmac.last_be import TXLastBE, RXLastBE
-from misoclib.ethmac.sram import SRAMWriter, SRAMReader
-
-class EthMAC(Module, AutoCSR):
-       def __init__(self, phy, interface="wishbone", with_hw_preamble_crc=True, endianness="be"):
-               # Preamble / CRC (optional)
-               if with_hw_preamble_crc:
-                       self._hw_preamble_crc = CSRStatus(reset=1)
-                       # Preamble insert/check
-                       preamble_inserter = PreambleInserter(phy.dw)
-                       preamble_checker = PreambleChecker(phy.dw)
-                       self.submodules += RenameClockDomains(preamble_inserter, "eth_tx")
-                       self.submodules += RenameClockDomains(preamble_checker, "eth_rx")
-
-                       # CRC insert/check
-                       crc32_inserter = CRC32Inserter(eth_description(phy.dw))
-                       crc32_checker = CRC32Checker(eth_description(phy.dw))
-                       self.submodules += RenameClockDomains(crc32_inserter, "eth_tx")
-                       self.submodules += RenameClockDomains(crc32_checker, "eth_rx")
-
-               # Delimiters
-               tx_last_be = TXLastBE(phy.dw)
-               rx_last_be = RXLastBE(phy.dw)
-               self.submodules += RenameClockDomains(tx_last_be, "eth_tx")
-               self.submodules += RenameClockDomains(rx_last_be, "eth_rx")
-
-               # Converters
-               reverse = endianness == "be"
-               tx_converter = Converter(eth_description(32), eth_description(phy.dw), reverse=reverse)
-               rx_converter = Converter(eth_description(phy.dw), eth_description(32), reverse=reverse)
-               self.submodules += RenameClockDomains(tx_converter, "eth_tx")
-               self.submodules += RenameClockDomains(rx_converter, "eth_rx")
-
-               # Cross Domain Crossing
-               tx_cdc = AsyncFIFO(eth_description(32), 4)
-               rx_cdc = AsyncFIFO(eth_description(32), 4)
-               self.submodules +=  RenameClockDomains(tx_cdc, {"write": "sys", "read": "eth_tx"})
-               self.submodules +=  RenameClockDomains(rx_cdc, {"write": "eth_rx", "read": "sys"})
-
-               # Graph
-               if with_hw_preamble_crc:
-                       rx_pipeline = [phy, preamble_checker, crc32_checker, rx_last_be, rx_converter, rx_cdc]
-                       tx_pipeline = [tx_cdc, tx_converter, tx_last_be, crc32_inserter, preamble_inserter, phy]
-               else:
-                       rx_pipeline = [phy, rx_last_be, rx_converter, rx_cdc]
-                       tx_pipeline = [tx_cdc, tx_converter, tx_last_be, phy]
-               self.submodules.rx_pipeline = Pipeline(*rx_pipeline)
-               self.submodules.tx_pipeline = Pipeline(*tx_pipeline)
+class LiteEthernetMAC(Module, AutoCSR):
+       def __init__(self, phy, frontend="wishbone", with_hw_preamble_crc=True, endianness="be"):
+               self.submodules.core = LiteEthernetMAC(phy, with_hw_preamble, endianness)
 
                if interface == "wishbone":
                        nrxslots = 2
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a361d5dcb76282c26e0790d1de9ecb066fed0a7f 100644 (file)
@@ -0,0 +1,54 @@
+
+from liteethernet.common import *
+from liteethernet.mac.common import *
+from liteethernet.mac.preamble import PreambleInserter, PreambleChecker
+from liteethernet.mac.crc import CRC32Inserter, CRC32Checker
+from liteethernet.mac.last_be import TXLastBE, RXLastBE
+
+class LiteEthernetMACCore(Module, AutoCSR):
+       def __init__(self, phy, with_hw_preamble_crc=True, endianness="be"):
+               # Preamble / CRC (optional)
+               if with_hw_preamble_crc:
+                       self._hw_preamble_crc = CSRStatus(reset=1)
+                       # Preamble insert/check
+                       preamble_inserter = PreambleInserter(phy.dw)
+                       preamble_checker = PreambleChecker(phy.dw)
+                       self.submodules += RenameClockDomains(preamble_inserter, "eth_tx")
+                       self.submodules += RenameClockDomains(preamble_checker, "eth_rx")
+
+                       # CRC insert/check
+                       crc32_inserter = CRC32Inserter(eth_description(phy.dw))
+                       crc32_checker = CRC32Checker(eth_description(phy.dw))
+                       self.submodules += RenameClockDomains(crc32_inserter, "eth_tx")
+                       self.submodules += RenameClockDomains(crc32_checker, "eth_rx")
+
+               # Delimiters
+               tx_last_be = TXLastBE(phy.dw)
+               rx_last_be = RXLastBE(phy.dw)
+               self.submodules += RenameClockDomains(tx_last_be, "eth_tx")
+               self.submodules += RenameClockDomains(rx_last_be, "eth_rx")
+
+               # Converters
+               reverse = endianness == "be"
+               tx_converter = Converter(eth_description(32), eth_description(phy.dw), reverse=reverse)
+               rx_converter = Converter(eth_description(phy.dw), eth_description(32), reverse=reverse)
+               self.submodules += RenameClockDomains(tx_converter, "eth_tx")
+               self.submodules += RenameClockDomains(rx_converter, "eth_rx")
+
+               # Cross Domain Crossing
+               tx_cdc = AsyncFIFO(eth_description(32), 4)
+               rx_cdc = AsyncFIFO(eth_description(32), 4)
+               self.submodules +=  RenameClockDomains(tx_cdc, {"write": "sys", "read": "eth_tx"})
+               self.submodules +=  RenameClockDomains(rx_cdc, {"write": "eth_rx", "read": "sys"})
+
+               # Graph
+               if with_hw_preamble_crc:
+                       rx_pipeline = [phy, preamble_checker, crc32_checker, rx_last_be, rx_converter, rx_cdc]
+                       tx_pipeline = [tx_cdc, tx_converter, tx_last_be, crc32_inserter, preamble_inserter, phy]
+               else:
+                       rx_pipeline = [phy, rx_last_be, rx_converter, rx_cdc]
+                       tx_pipeline = [tx_cdc, tx_converter, tx_last_be, phy]
+               self.submodules.rx_pipeline = Pipeline(*rx_pipeline)
+               self.submodules.tx_pipeline = Pipeline(*tx_pipeline)
+
+               self.sink, self.source = self.tx_pipeline.sink, self.rx_pipeline.source
diff --git a/liteethernet/mac/core/crc.py b/liteethernet/mac/core/crc.py
new file mode 100644 (file)
index 0000000..8a058fa
--- /dev/null
@@ -0,0 +1,284 @@
+from migen.fhdl.std import *
+from migen.genlib.fsm import FSM, NextState
+from migen.genlib.record import *
+from migen.genlib.misc import optree, chooser
+from migen.genlib.crc import *
+from migen.flow.actor import Sink, Source
+from migen.actorlib.fifo import SyncFIFO
+
+from collections import OrderedDict
+
+class CRCEngine(Module):
+       """Cyclic Redundancy Check Engine
+
+       Compute next CRC value from last CRC value and data input using
+       an optimized asynchronous LFSR.
+
+       Parameters
+       ----------
+       dat_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
+       ----------
+       d : in
+               Data input.
+       last : in
+               last CRC value.
+       next :
+               next CRC value.
+       """
+       def __init__(self, dat_width, width, polynom):
+               self.d = Signal(dat_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(dat_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.d[n]]
+                       self.comb += self.next[i].eq(optree("^", xors))
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class CRC32(Module):
+       """IEEE 802.3 CRC
+
+       Implement an IEEE 802.3 CRC generator/checker.
+
+       Parameters
+       ----------
+       dat_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, dat_width):
+               self.d = Signal(dat_width)
+               self.value = Signal(self.width)
+               self.error = Signal()
+
+               ###
+
+               self.submodules.engine = CRCEngine(dat_width, self.width, self.polynom)
+               reg = Signal(self.width, reset=self.init)
+               self.sync += reg.eq(self.engine.next)
+               self.comb += [
+                       self.engine.d.eq(self.d),
+                       self.engine.last.eq(reg),
+
+                       self.value.eq(~reg[::-1]),
+                       self.error.eq(self.engine.next != self.check)
+               ]
+
+class CRCInserter(Module):
+       """CRC Inserter
+
+       Append a CRC at the end of each packet.
+
+       Parameters
+       ----------
+       layout : layout
+               Layout of the dataflow.
+
+       Attributes
+       ----------
+       sink : in
+               Packets input without CRC.
+       source : out
+               Packets output with CRC.
+       """
+       def __init__(self, crc_class, layout):
+               self.sink = sink = Sink(layout)
+               self.source = source = Source(layout)
+               self.busy = Signal()
+
+               ###
+
+               dw = flen(sink.d)
+               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.d.eq(sink.d),
+                       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.d, 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.d.eq(crc.value),
+                               If(source.ack, NextState("IDLE"))
+                       )
+               self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
+
+class CRC32Inserter(CRCInserter):
+       def __init__(self, layout):
+               CRCInserter.__init__(self, CRC32, layout)
+
+class CRCChecker(Module):
+       """CRC Checker
+
+       Check CRC at the end of each packet.
+
+       Parameters
+       ----------
+       layout : layout
+               Layout 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, layout):
+               self.sink = sink = Sink(layout)
+               self.source = source = Source(layout)
+               self.busy = Signal()
+
+               ###
+
+               dw = flen(sink.d)
+               crc = crc_class(dw)
+               self.submodules += crc
+               ratio = crc.width//dw
+
+               error = Signal()
+               fifo = InsertReset(SyncFIFO(layout, 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"),
+               )
+               fsm.act("IDLE",
+                       crc.d.eq(sink.d),
+                       If(sink.stb & sink.sop & sink.ack,
+                               crc.ce.eq(1),
+                               NextState("COPY")
+                       )
+               )
+               fsm.act("COPY",
+                       crc.d.eq(sink.d),
+                       If(sink.stb & sink.ack,
+                               crc.ce.eq(1),
+                               If(sink.eop,
+                                       NextState("RESET")
+                               )
+                       )
+               )
+               self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
+
+class CRC32Checker(CRCChecker):
+       def __init__(self, layout):
+               CRCChecker.__init__(self, CRC32, layout)
index da55faee17e005ea71e14990b0d220158b671ce1..555e523f5dc658e85aa5e5b6593c3eee9b606fab 100644 (file)
@@ -2,7 +2,8 @@ from migen.fhdl.std import *
 from migen.genlib.record import *
 from migen.flow.actor import Sink, Source
 
-from misoclib.ethmac.common import *
+from liteethernet.common import *
+from liteethernet.mac.common import *
 
 class TXLastBE(Module):
        def __init__(self, d_w):
index fe2078fee4acb1cca58441ebafeaf8d141207a7b..f1c760347250cf5db467ab9b21bc4c7f6a4dc95e 100644 (file)
@@ -4,7 +4,8 @@ from migen.genlib.misc import chooser
 from migen.genlib.record import *
 from migen.flow.actor import Sink, Source
 
-from misoclib.ethmac.common import *
+from liteethernet.common import *
+from liteethernet.ethmac.common import *
 
 class PreambleInserter(Module):
        def __init__(self, d_w):
index 32c76f3c03da7266378a9d50b7d8f1ecf899ef02..c51c0ecbee75e5a9b36b42598c9e6f46cf3de489 100644 (file)
@@ -6,7 +6,8 @@ from migen.flow.actor import Sink, Source
 from migen.bank.description import *
 from migen.bank.eventmanager import *
 
-from misoclib.ethmac.common import *
+from liteethernet.common import *
+from liteethernet.mac.common import *
 
 class SRAMWriter(Module, AutoCSR):
        def __init__(self, depth, nslots=2):
diff --git a/liteethernet/mac/frontend/wishbone.py b/liteethernet/mac/frontend/wishbone.py
new file mode 100644 (file)
index 0000000..56601e1
--- /dev/null
@@ -0,0 +1,39 @@
+from liteethernet.common import *
+from liteethernet.mac import LiteEthernetMAC
+
+class LiteEthernetMACWishboneInterface(Module, AutoCSR):
+       def __init__(self, nrxslots=2, ntxslots=2):
+               self.sink = Sink(mac_description(dw))
+               self.source = Source(max_description(dw))
+               self.bus = wishbone.Interface()
+
+               ###
+
+               # SRAM Storage
+               sram_depth = buffer_depth//(32//8)
+               self.submodules.sram_writer = SRAMWriter(sram_depth, nrxslots)
+               self.submodules.sram_reader = SRAMReader(sram_depth, ntxslots)
+               self.submodules.ev = SharedIRQ(self.sram_writer.ev, self.sram_reader.ev)
+               self.comb += [
+                       Record.connect(self.sink, self.sram_writer.sink),
+                       Record.connect(self.sram_reader.source, self.source)
+               ]
+
+               # 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
diff --git a/liteethernet/mac/phy/__init__.py b/liteethernet/mac/phy/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/liteethernet/mac/phy/gmii.py b/liteethernet/mac/phy/gmii.py
deleted file mode 100644 (file)
index ebdd023..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-from migen.fhdl.std import *
-from migen.flow.actor import Sink, Source
-from migen.bank.description import *
-from migen.genlib.resetsync import AsyncResetSynchronizer
-
-from misoclib.ethmac.common import *
-
-class GMIIPHYTX(Module):
-       def __init__(self, pads):
-               self.sink = sink = Sink(eth_description(8))
-
-               ###
-
-               self.sync += [
-                       pads.tx_er.eq(0),
-                       pads.tx_en.eq(sink.stb),
-                       pads.tx_data.eq(sink.d)
-               ]
-               self.comb += sink.ack.eq(1)
-
-class GMIIPHYRX(Module):
-       def __init__(self, pads):
-               self.source = source = Source(eth_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.d.eq(pads.rx_data)
-               ]
-               self.comb += source.eop.eq(eop)
-
-# CRG is the only Xilinx specific module.
-# TODO: use generic code or add support for others vendors
-class GMIIPHYCRG(Module, AutoCSR):
-       def __init__(self, clock_pads, pads):
-               self._reset = CSRStorage()
-
-               ###
-
-               self.clock_domains.cd_eth_rx = ClockDomain()
-               self.clock_domains.cd_eth_tx = ClockDomain()
-               self.specials += [
-                       Instance("ODDR",
-                               p_DDR_CLK_EDGE="SAME_EDGE",
-                               i_C=ClockSignal("eth_tx"), i_CE=1, i_S=0, i_R=0,
-                               i_D1=1, i_D2=0, o_Q=clock_pads.gtx,
-                       ),
-                       Instance("BUFG", i_I=clock_pads.rx, o_O=self.cd_eth_rx.clk),
-               ]
-               self.comb += self.cd_eth_tx.clk.eq(self.cd_eth_rx.clk)
-
-               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 GMIIPHY(Module, AutoCSR):
-       def __init__(self, clock_pads, pads):
-               self.dw = 8
-               self.submodules.crg = GMIIPHYCRG(clock_pads, pads)
-               self.submodules.tx = RenameClockDomains(GMIIPHYTX(pads), "eth_tx")
-               self.submodules.rx = RenameClockDomains(GMIIPHYRX(pads), "eth_rx")
-               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/liteethernet/mac/phy/loopback.py b/liteethernet/mac/phy/loopback.py
deleted file mode 100644 (file)
index 50c9f99..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-from migen.fhdl.std import *
-from migen.flow.actor import Sink, Source
-from migen.bank.description import *
-from migen.genlib.record import *
-
-from misoclib.ethmac.common import *
-
-class LoopbackPHYCRG(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 LoopbackPHY(Module, AutoCSR):
-       def __init__(self):
-               self.dw = 8
-               self.submodules.crg = LoopbackPHYCRG()
-               self.sink = sink = Sink(eth_description(8))
-               self.source = source = Source(eth_description(8))
-               self.comb += Record.connect(self.sink, self.source)
diff --git a/liteethernet/mac/phy/mii.py b/liteethernet/mac/phy/mii.py
deleted file mode 100644 (file)
index 17f2ba7..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-from migen.fhdl.std import *
-from migen.genlib.fsm import FSM, NextState
-from migen.flow.actor import Sink, Source
-from migen.bank.description import *
-from migen.genlib.resetsync import AsyncResetSynchronizer
-
-from misoclib.ethmac.common import *
-
-class MIIPHYTX(Module):
-       def __init__(self, pads):
-               self.sink = sink = Sink(eth_description(8))
-
-               ###
-
-               tx_en_r = Signal()
-               tx_data_r = Signal(4)
-               self.sync += [
-                       pads.tx_er.eq(0),
-                       pads.tx_en.eq(tx_en_r),
-                       pads.tx_data.eq(tx_data_r),
-               ]
-
-               fsm = FSM(reset_state="IDLE")
-               self.submodules += fsm
-               fsm.act("IDLE",
-                       sink.ack.eq(1),
-                       If(sink.stb & sink.sop,
-                               sink.ack.eq(0),
-                               NextState("SEND_LO")
-                       )
-               )
-               fsm.act("SEND_LO",
-                       tx_data_r.eq(sink.d[0:4]),
-                       tx_en_r.eq(1),
-                       NextState("SEND_HI")
-               )
-               fsm.act("SEND_HI",
-                       tx_data_r.eq(sink.d[4:8]),
-                       tx_en_r.eq(1),
-                       sink.ack.eq(1),
-                       If(sink.stb & sink.eop,
-                               NextState("IDLE")
-                       ).Else(
-                               NextState("SEND_LO")
-                       )
-               )
-
-class MIIPHYRX(Module):
-       def __init__(self, pads):
-               self.source = source = Source(eth_description(8))
-
-               ###
-
-               sop = source.sop
-               set_sop = Signal()
-               clr_sop = Signal()
-               self.sync += \
-                       If(clr_sop,
-                               sop.eq(0)
-                       ).Elif(set_sop,
-                               sop.eq(1)
-                       )
-
-               lo = Signal(4)
-               hi = Signal(4)
-               load_nibble = Signal(2)
-               self.sync  += \
-                       If(load_nibble[0],
-                               lo.eq(pads.rx_data)
-                       ).Elif(load_nibble[1],
-                               hi.eq(pads.rx_data)
-                       )
-               self.comb += [
-                       source.d.eq(Cat(lo, hi))
-               ]
-
-               fsm = FSM(reset_state="IDLE")
-               self.submodules += fsm
-               fsm.act("IDLE",
-                       set_sop.eq(1),
-                       If(pads.dv,
-                               load_nibble.eq(0b01),
-                               NextState("LOAD_HI")
-                       )
-               )
-               fsm.act("LOAD_LO",
-                       source.stb.eq(1),
-                       If(pads.dv,
-                               clr_sop.eq(1),
-                               load_nibble.eq(0b01),
-                               NextState("LOAD_HI")
-                       ).Else(
-                               source.eop.eq(1),
-                               NextState("IDLE")
-                       )
-               )
-               fsm.act("LOAD_HI",
-                       load_nibble.eq(0b10),
-                       NextState("LOAD_LO")
-               )
-
-class MIIPHYCRG(Module, AutoCSR):
-       def __init__(self, clock_pads, pads):
-               self._reset = CSRStorage()
-
-               ###
-
-               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)
-
-               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 MIIPHY(Module, AutoCSR):
-       def __init__(self, clock_pads, pads):
-               self.dw = 8
-               self.submodules.crg = MIIPHYCRG(clock_pads, pads)
-               self.submodules.tx = RenameClockDomains(MIIPHYTX(pads), "eth_tx")
-               self.submodules.rx = RenameClockDomains(MIIPHYRX(pads), "eth_rx")
-               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/liteethernet/phy/__init__.py b/liteethernet/phy/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/liteethernet/phy/gmii.py b/liteethernet/phy/gmii.py
new file mode 100644 (file)
index 0000000..c1b8243
--- /dev/null
@@ -0,0 +1,70 @@
+from migen.fhdl.std import *
+from migen.flow.actor import Sink, Source
+from migen.bank.description import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+
+from liteethernet.common import *
+
+class GMIIPHYTX(Module):
+       def __init__(self, pads):
+               self.sink = sink = Sink(eth_description(8))
+               ###
+               self.sync += [
+                       pads.tx_er.eq(0),
+                       pads.tx_en.eq(sink.stb),
+                       pads.tx_data.eq(sink.d)
+               ]
+               self.comb += sink.ack.eq(1)
+
+class GMIIPHYRX(Module):
+       def __init__(self, pads):
+               self.source = source = Source(eth_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.d.eq(pads.rx_data)
+               ]
+               self.comb += source.eop.eq(eop)
+
+# CRG is the only Xilinx specific module.
+# TODO: use generic code or add support for others vendors
+class GMIIPHYCRG(Module, AutoCSR):
+       def __init__(self, clock_pads, pads):
+               self._reset = CSRStorage()
+               ###
+               self.clock_domains.cd_eth_rx = ClockDomain()
+               self.clock_domains.cd_eth_tx = ClockDomain()
+               self.specials += [
+                       Instance("ODDR",
+                               p_DDR_CLK_EDGE="SAME_EDGE",
+                               i_C=ClockSignal("eth_tx"), i_CE=1, i_S=0, i_R=0,
+                               i_D1=1, i_D2=0, o_Q=clock_pads.gtx,
+                       ),
+                       Instance("BUFG", i_I=clock_pads.rx, o_O=self.cd_eth_rx.clk),
+               ]
+               self.comb += self.cd_eth_tx.clk.eq(self.cd_eth_rx.clk)
+
+               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 GMIIPHY(Module, AutoCSR):
+       def __init__(self, clock_pads, pads):
+               self.dw = 8
+               self.submodules.crg = GMIIPHYCRG(clock_pads, pads)
+               self.submodules.tx = RenameClockDomains(GMIIPHYTX(pads), "eth_tx")
+               self.submodules.rx = RenameClockDomains(GMIIPHYRX(pads), "eth_rx")
+               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/liteethernet/phy/loopback.py b/liteethernet/phy/loopback.py
new file mode 100644 (file)
index 0000000..04a51d0
--- /dev/null
@@ -0,0 +1,31 @@
+from migen.fhdl.std import *
+from migen.flow.actor import Sink, Source
+from migen.bank.description import *
+from migen.genlib.record import *
+
+from liteethernet.common import *
+
+class LoopbackPHYCRG(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 LoopbackPHY(Module, AutoCSR):
+       def __init__(self):
+               self.dw = 8
+               self.submodules.crg = LoopbackPHYCRG()
+               self.sink = sink = Sink(eth_description(8))
+               self.source = source = Source(eth_description(8))
+               self.comb += Record.connect(self.sink, self.source)
diff --git a/liteethernet/phy/mii.py b/liteethernet/phy/mii.py
new file mode 100644 (file)
index 0000000..a58b52b
--- /dev/null
@@ -0,0 +1,122 @@
+from migen.fhdl.std import *
+from migen.genlib.fsm import FSM, NextState
+from migen.flow.actor import Sink, Source
+from migen.bank.description import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+
+from liteethernet.common import *
+
+class MIIPHYTX(Module):
+       def __init__(self, pads):
+               self.sink = sink = Sink(eth_description(8))
+               ###
+               tx_en_r = Signal()
+               tx_data_r = Signal(4)
+               self.sync += [
+                       pads.tx_er.eq(0),
+                       pads.tx_en.eq(tx_en_r),
+                       pads.tx_data.eq(tx_data_r),
+               ]
+
+               fsm = FSM(reset_state="IDLE")
+               self.submodules += fsm
+               fsm.act("IDLE",
+                       sink.ack.eq(1),
+                       If(sink.stb & sink.sop,
+                               sink.ack.eq(0),
+                               NextState("SEND_LO")
+                       )
+               )
+               fsm.act("SEND_LO",
+                       tx_data_r.eq(sink.d[0:4]),
+                       tx_en_r.eq(1),
+                       NextState("SEND_HI")
+               )
+               fsm.act("SEND_HI",
+                       tx_data_r.eq(sink.d[4:8]),
+                       tx_en_r.eq(1),
+                       sink.ack.eq(1),
+                       If(sink.stb & sink.eop,
+                               NextState("IDLE")
+                       ).Else(
+                               NextState("SEND_LO")
+                       )
+               )
+
+class MIIPHYRX(Module):
+       def __init__(self, pads):
+               self.source = source = Source(eth_description(8))
+               ###
+               sop = source.sop
+               set_sop = Signal()
+               clr_sop = Signal()
+               self.sync += \
+                       If(clr_sop,
+                               sop.eq(0)
+                       ).Elif(set_sop,
+                               sop.eq(1)
+                       )
+
+               lo = Signal(4)
+               hi = Signal(4)
+               load_nibble = Signal(2)
+               self.sync  += \
+                       If(load_nibble[0],
+                               lo.eq(pads.rx_data)
+                       ).Elif(load_nibble[1],
+                               hi.eq(pads.rx_data)
+                       )
+               self.comb += [
+                       source.d.eq(Cat(lo, hi))
+               ]
+
+               fsm = FSM(reset_state="IDLE")
+               self.submodules += fsm
+               fsm.act("IDLE",
+                       set_sop.eq(1),
+                       If(pads.dv,
+                               load_nibble.eq(0b01),
+                               NextState("LOAD_HI")
+                       )
+               )
+               fsm.act("LOAD_LO",
+                       source.stb.eq(1),
+                       If(pads.dv,
+                               clr_sop.eq(1),
+                               load_nibble.eq(0b01),
+                               NextState("LOAD_HI")
+                       ).Else(
+                               source.eop.eq(1),
+                               NextState("IDLE")
+                       )
+               )
+               fsm.act("LOAD_HI",
+                       load_nibble.eq(0b10),
+                       NextState("LOAD_LO")
+               )
+
+class MIIPHYCRG(Module, AutoCSR):
+       def __init__(self, clock_pads, pads):
+               self._reset = CSRStorage()
+               ###
+               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)
+
+               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 MIIPHY(Module, AutoCSR):
+       def __init__(self, clock_pads, pads):
+               self.dw = 8
+               self.submodules.crg = MIIPHYCRG(clock_pads, pads)
+               self.submodules.tx = RenameClockDomains(MIIPHYTX(pads), "eth_tx")
+               self.submodules.rx = RenameClockDomains(MIIPHYRX(pads), "eth_rx")
+               self.sink, self.source = self.tx.sink, self.rx.source