diff --git a/liteeth/common.py b/liteeth/common.py index 177943ee5..9f4a1d6eb 100644 --- a/liteeth/common.py +++ b/liteeth/common.py @@ -1,4 +1,10 @@ +from collections import OrderedDict + from migen.fhdl.std import * +from migen.fhdl.std import * +from migen.flow.actor import Sink, Source +from migen.bank.description import * +from migen.genlib.resetsync import AsyncResetSynchronizer from migen.flow.actor import EndpointDescription eth_mtu = 1532 diff --git a/liteeth/mac/__init__.py b/liteeth/mac/__init__.py index e9b2ccfaa..280fbdf7a 100644 --- a/liteeth/mac/__init__.py +++ b/liteeth/mac/__init__.py @@ -1,54 +1,17 @@ -from liteethernet.common import * -from liteethernet.mac import LiteEthernetMAC - -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) +from liteeth.common import * +from liteeth.mac.core import LiteEthMACCore +from liteeth.mac.frontend import wishbone +class LiteEthMAC(Module, AutoCSR): + def __init__(self, phy, interface="wishbone", dw, endianness="be", + with_hw_preamble_crc=True): + self.submodules.core = LiteEthMACCore(phy, endianness, with_hw_preamble) if interface == "wishbone": - nrxslots = 2 - ntxslots = 2 - - self.bus = wishbone.Interface() - - # SRAM Memories - 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) - - # Connect to pipelines - self.comb += [ - self.rx_pipeline.source.connect(self.sram_writer.sink), - self.sram_reader.source.connect(self.tx_pipeline.sink) - ] - - # 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 - - elif interface == "lasmi": + self.interface = wishbone.LiteETHMACWishboneInterface(), dw, nrxslots, ntxslots) + elif interface == "dma": raise NotImplementedError - - elif interface == "expose": - # expose pipelines endpoints - self.sink = tx_pipeline.sink - self.source = rx_pipeline.source - + elif interface == "core": + self.sink = self.core.sink + self.source = self.core.source else: - raise ValueError("EthMAC only supports Wishbone, LASMI or expose interfaces") + raise ValueError("EthMAC only supports Wishbone, DMA or core interfaces") diff --git a/liteeth/mac/common.py b/liteeth/mac/common.py index 177943ee5..e69de29bb 100644 --- a/liteeth/mac/common.py +++ b/liteeth/mac/common.py @@ -1,14 +0,0 @@ -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) diff --git a/liteeth/mac/core/__init__.py b/liteeth/mac/core/__init__.py index a361d5dcb..5e223f0c6 100644 --- a/liteeth/mac/core/__init__.py +++ b/liteeth/mac/core/__init__.py @@ -1,43 +1,42 @@ +from liteeth.common import * +from liteeth.mac.common import * +from liteeth.mac import preamble, crc, last_be -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"): +class LiteEthMACCore(Module, AutoCSR): + def __init__(self, phy, dw, endianness="be", with_hw_preamble_crc=True): + if dw > phy.dw: + raise ValueError("Core data width must be larger than PHY data width") # 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) + preamble_inserter = preamble.LiteEthMACPreambleInserter(phy.dw) + preamble_checker = preamble.LiteEthMACPreambleChecker(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)) + crc32_inserter = crc.LiteEthMACCRC32Inserter(eth_description(phy.dw)) + crc32_checker = crc.LiteEthMACCRC32Checker(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) + tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw) + rx_last_be = last_be.LiteEthMACRXLastBE(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) + tx_converter = Converter(eth_description(dw), eth_description(phy.dw), reverse=reverse) + rx_converter = Converter(eth_description(phy.dw), eth_description(dw), 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) + tx_cdc = AsyncFIFO(eth_description(dw), 4) + rx_cdc = AsyncFIFO(eth_description(dw), 4) self.submodules += RenameClockDomains(tx_cdc, {"write": "sys", "read": "eth_tx"}) self.submodules += RenameClockDomains(rx_cdc, {"write": "eth_rx", "read": "sys"}) diff --git a/liteeth/mac/core/crc.py b/liteeth/mac/core/crc.py index 8a058faeb..f77c5e0df 100644 --- a/liteeth/mac/core/crc.py +++ b/liteeth/mac/core/crc.py @@ -1,14 +1,7 @@ -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 liteeth.common import * +from liteeth.mac.common import * -from collections import OrderedDict - -class CRCEngine(Module): +class LiteEthMACCRCEngine(Module): """Cyclic Redundancy Check Engine Compute next CRC value from last CRC value and data input using @@ -78,7 +71,7 @@ class CRCEngine(Module): @DecorateModule(InsertReset) @DecorateModule(InsertCE) -class CRC32(Module): +class LiteEthMACCRC32(Module): """IEEE 802.3 CRC Implement an IEEE 802.3 CRC generator/checker. @@ -108,7 +101,7 @@ class CRC32(Module): ### - self.submodules.engine = CRCEngine(dat_width, self.width, self.polynom) + self.submodules.engine = LiteEthCRCEngine(dat_width, self.width, self.polynom) reg = Signal(self.width, reset=self.init) self.sync += reg.eq(self.engine.next) self.comb += [ @@ -119,7 +112,7 @@ class CRC32(Module): self.error.eq(self.engine.next != self.check) ] -class CRCInserter(Module): +class LiteEthMACCRCInserter(Module): """CRC Inserter Append a CRC at the end of each packet. @@ -193,11 +186,11 @@ class CRCInserter(Module): ) self.comb += self.busy.eq(~fsm.ongoing("IDLE")) -class CRC32Inserter(CRCInserter): +class LiteEthMACCRC32Inserter(CRCInserter): def __init__(self, layout): - CRCInserter.__init__(self, CRC32, layout) + LiteEthMACCRCInserter.__init__(self, LiteEthMACCRC32, layout) -class CRCChecker(Module): +class LiteEthMACCRCChecker(Module): """CRC Checker Check CRC at the end of each packet. @@ -279,6 +272,6 @@ class CRCChecker(Module): ) self.comb += self.busy.eq(~fsm.ongoing("IDLE")) -class CRC32Checker(CRCChecker): +class LiteEthMACCRC32Checker(CRCChecker): def __init__(self, layout): - CRCChecker.__init__(self, CRC32, layout) + LiteEthMACCRCChecker.__init__(self, LiteEthMACCRC32, layout) diff --git a/liteeth/mac/core/last_be.py b/liteeth/mac/core/last_be.py index 555e523f5..cfab1c696 100644 --- a/liteeth/mac/core/last_be.py +++ b/liteeth/mac/core/last_be.py @@ -1,11 +1,7 @@ -from migen.fhdl.std import * -from migen.genlib.record import * -from migen.flow.actor import Sink, Source +from liteeth.common import * +from liteeth.mac.common import * -from liteethernet.common import * -from liteethernet.mac.common import * - -class TXLastBE(Module): +class LiteEthMACTXLastBE(Module): def __init__(self, d_w): self.sink = sink = Sink(eth_description(d_w)) self.source = source = Source(eth_description(d_w)) @@ -27,7 +23,7 @@ class TXLastBE(Module): self.source.stb.eq(self.sink.stb & (self.sink.sop | ongoing)) ] -class RXLastBE(Module): +class LiteEthMACRXLastBE(Module): def __init__(self, d_w): self.sink = sink = Sink(eth_description(d_w)) self.source = source = Source(eth_description(d_w)) diff --git a/liteeth/mac/core/preamble.py b/liteeth/mac/core/preamble.py index f1c760347..9f4cb0ccb 100644 --- a/liteeth/mac/core/preamble.py +++ b/liteeth/mac/core/preamble.py @@ -1,13 +1,7 @@ -from migen.fhdl.std import * -from migen.genlib.fsm import FSM, NextState -from migen.genlib.misc import chooser -from migen.genlib.record import * -from migen.flow.actor import Sink, Source +from liteeth.common import * +from liteeth.mac.common import * -from liteethernet.common import * -from liteethernet.ethmac.common import * - -class PreambleInserter(Module): +class LiteEthMACPreambleInserter(Module): def __init__(self, d_w): self.sink = Sink(eth_description(d_w)) self.source = Source(eth_description(d_w)) @@ -56,7 +50,7 @@ class PreambleInserter(Module): ) ) -class PreambleChecker(Module): +class LiteEthMACPreambleChecker(Module): def __init__(self, d_w): self.sink = Sink(eth_description(d_w)) self.source = Source(eth_description(d_w)) diff --git a/liteeth/mac/frontend/sram.py b/liteeth/mac/frontend/sram.py index c51c0ecbe..ec4f963bd 100644 --- a/liteeth/mac/frontend/sram.py +++ b/liteeth/mac/frontend/sram.py @@ -1,17 +1,9 @@ -from migen.fhdl.std import * -from migen.genlib.fifo import SyncFIFO -from migen.genlib.fsm import FSM, NextState -from migen.genlib.misc import chooser -from migen.flow.actor import Sink, Source -from migen.bank.description import * -from migen.bank.eventmanager import * +from liteeth.common import * +from liteeth.mac.common import * -from liteethernet.common import * -from liteethernet.mac.common import * - -class SRAMWriter(Module, AutoCSR): - def __init__(self, depth, nslots=2): - self.sink = sink = Sink(eth_description(32)) +class LiteEthMACSRAMWriter(Module, AutoCSR): + def __init__(self, dw, depth, nslots=2): + self.sink = sink = Sink(eth_description(dw)) self.crc_error = Signal() slotbits = max(log2_int(nslots), 1) @@ -117,7 +109,7 @@ class SRAMWriter(Module, AutoCSR): mems = [None]*nslots ports = [None]*nslots for n in range(nslots): - mems[n] = Memory(32, depth) + mems[n] = Memory(dw, depth) ports[n] = mems[n].get_port(write_capable=True) self.specials += ports[n] self.mems = mems @@ -134,9 +126,9 @@ class SRAMWriter(Module, AutoCSR): self.comb += Case(slot, cases) -class SRAMReader(Module, AutoCSR): - def __init__(self, depth, nslots=2): - self.source = source = Source(eth_description(32)) +class LiteEthMACSRAMReader(Module, AutoCSR): + def __init__(self, dw, depth, nslots=2): + self.source = source = Source(eth_description(dw)) slotbits = max(log2_int(nslots), 1) lengthbits = log2_int(depth*4) # length in bytes @@ -240,7 +232,7 @@ class SRAMReader(Module, AutoCSR): mems = [None]*nslots ports = [None]*nslots for n in range(nslots): - mems[n] = Memory(32, depth) + mems[n] = Memory(dw, depth) ports[n] = mems[n].get_port() self.specials += ports[n] self.mems = mems @@ -250,3 +242,10 @@ class SRAMReader(Module, AutoCSR): self.comb += ports[n].adr.eq(cnt[2:]) cases[n] = [source.d.eq(port.dat_r)] self.comb += Case(rd_slot, cases) + +class LiteMACEthMACSRAM(Module, AutoCSR): + def __init__(self, dw, depth, nrxslots, ntxslots): + self.submodules.writer = LiteEthSRAMWriter(dw, depth, nrxslots) + self.submodules.reader = LiteEthSRAMReader(dw, depth, ntxslots) + self.submodules.ev = SharedIRQ(self.writer.ev, self.reader.ev) + self.sink, self.source = self.witer.sink, self.reader.source diff --git a/liteeth/mac/frontend/wishbone.py b/liteeth/mac/frontend/wishbone.py index 56601e126..c81590181 100644 --- a/liteeth/mac/frontend/wishbone.py +++ b/liteeth/mac/frontend/wishbone.py @@ -1,25 +1,22 @@ -from liteethernet.common import * -from liteethernet.mac import LiteEthernetMAC +from liteeth.common import * +from liteeth.mac.common import * +from liteeth.mac.frontend import sram -class LiteEthernetMACWishboneInterface(Module, AutoCSR): - def __init__(self, nrxslots=2, ntxslots=2): +class LiteEthMACWishboneInterface(Module, AutoCSR): + def __init__(self, dw, 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) + # 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_writer.sink), - Record.connect(self.sram_reader.source, self.source) + Record.connect(self.sink, self.sram.sink), + Record.connect(self.sram.source, self.source) ] - # Interface + # 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 diff --git a/liteeth/mac/test/Makefile b/liteeth/mac/test/Makefile deleted file mode 100644 index 55d28e10a..000000000 --- a/liteeth/mac/test/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -MSCDIR = ../../../ -PYTHON = python3 - -CMD = PYTHONPATH=$(MSCDIR) $(PYTHON) - -crc_tb: - $(CMD) crc_tb.py - -preamble_tb: - $(CMD) preamble_tb.py - -ethmac_tb: - $(CMD) ethmac_tb.py diff --git a/liteeth/mac/test/crc_tb.py b/liteeth/mac/test/crc_tb.py deleted file mode 100644 index 5d185ac18..000000000 --- a/liteeth/mac/test/crc_tb.py +++ /dev/null @@ -1,83 +0,0 @@ -from migen.fhdl.std import * -from migen.actorlib.crc import * - -from misoclib.ethmac.common import * -from misoclib.ethmac.test.common import * - -payload = [ - 0x00, 0x0A, 0xE6, 0xF0, 0x05, 0xA3, 0x00, 0x12, - 0x34, 0x56, 0x78, 0x90, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x30, 0xB3, 0xFE, 0x00, 0x00, 0x80, 0x11, - 0x72, 0xBA, 0x0A, 0x00, 0x00, 0x03, 0x0A, 0x00, - 0x00, 0x02, 0x04, 0x00, 0x04, 0x00, 0x00, 0x1C, - 0x89, 0x4D, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, - 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 -] - -crc = [ - 0x7A, 0xD5, 0x6B, 0xB3 -] - -mux = { - "inserter": 0, - "checker": 1, - "both": 2 -} - -class TB(Module): - def __init__(self, random_level=50): - sm = self.submodules - sm.streamer = PacketStreamer(eth_description(8)) - sm.streamer_randomizer = AckRandomizer(eth_description(8), random_level) - sm.logger = PacketLogger(eth_description(8)) - sm.logger_randomizer = AckRandomizer(eth_description(8), random_level) - - self.comb += [ - self.streamer.source.connect(self.streamer_randomizer.sink), - self.logger_randomizer.source.connect(self.logger.sink) - ] - - sm.crc32_inserter = CRC32Inserter(eth_description(8)) - sm.crc32_checker = CRC32Checker(eth_description(8)) - - self.mux = Signal(2) - self.comb += [ - If(self.mux == mux["inserter"], - self.streamer_randomizer.source.connect(self.crc32_inserter.sink), - self.crc32_inserter.source.connect(self.logger_randomizer.sink) - ).Elif(self.mux == mux["checker"], - self.streamer_randomizer.source.connect(self.crc32_checker.sink), - self.crc32_checker.source.connect(self.logger_randomizer.sink) - ).Elif(self.mux == mux["both"], - self.streamer_randomizer.source.connect(self.crc32_inserter.sink), - self.crc32_inserter.source.connect(self.crc32_checker.sink), - self.crc32_checker.source.connect(self.logger_randomizer.sink) - ) - ] - - def gen_simulation(self, selfp): - selfp.mux = mux["inserter"] - print("streamer --> crc32_inserter --> logger:") - self.streamer.send(Packet(payload)) - yield from self.logger.receive() - s, l, e = check(payload+crc, self.logger.packet) - print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e)) - - selfp.mux = mux["checker"] - print("streamer --> crc32_checker --> logger:") - self.streamer.send(Packet(payload+crc)) - yield from self.logger.receive() - s, l, e = check(payload, self.logger.packet) - print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e)) - - selfp.mux = mux["both"] - print("streamer --> crc32_inserter --> crc32_checker --> logger:") - self.streamer.send(Packet(payload)) - yield from self.logger.receive() - s, l, e = check(payload, self.logger.packet) - print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e)) - -if __name__ == "__main__": - from migen.sim.generic import run_simulation - run_simulation(TB(), ncycles=1000, vcd_name="my.vcd") diff --git a/liteeth/mac/test/ethmac_tb.gtkw b/liteeth/mac/test/ethmac_tb.gtkw deleted file mode 100644 index 350521a21..000000000 --- a/liteeth/mac/test/ethmac_tb.gtkw +++ /dev/null @@ -1,75 +0,0 @@ -[*] -[*] GTKWave Analyzer v3.3.46 (w)1999-2012 BSI -[*] Fri Oct 31 11:20:55 2014 -[*] -[dumpfile] "/home/florent/Dev/misoc/misoclib/ethmac/test/my.vcd" -[dumpfile_mtime] "Fri Oct 31 11:20:07 2014" -[dumpfile_size] 5152269 -[savefile] "/home/florent/Dev/misoc/misoclib/ethmac/test/ethmac_tb.gtkw" -[timestart] 0 -[size] 1548 849 -[pos] 101 171 -*-25.000000 34300000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -[treeopen] top. -[sst_width] 379 -[signals_width] 464 -[sst_expanded] 1 -[sst_vpaned_height] 485 -@200 --WISHBONE -@28 -top.dut.bus_ack -@22 -top.dut.bus_adr[29:0] -@28 -top.dut.bus_bte[1:0] -top.dut.bus_cti[2:0] -top.dut.bus_cyc -@22 -top.dut.bus_dat_r[31:0] -top.dut.bus_dat_w[31:0] -@28 -top.dut.bus_err -@22 -top.dut.bus_sel[3:0] -@28 -top.dut.bus_stb -top.dut.bus_we -@200 --SRAM_READER --> PHYTx -@28 -top.dut.sram_reader_source_ack -top.dut.sram_reader_source_eop -@22 -top.dut.sram_reader_source_payload_d[31:0] -top.dut.sram_reader_source_payload_error[3:0] -top.dut.sram_reader_source_payload_last_be[3:0] -@28 -top.dut.sram_reader_source_sop -top.dut.sram_reader_source_stb -@200 --LOOPBACK -@28 -top.dut.phy_source_ack -top.dut.phy_source_eop -@22 -top.dut.phy_source_payload_d[7:0] -@28 -top.dut.phy_source_payload_error -top.dut.phy_source_payload_last_be -top.dut.phy_source_sop -top.dut.phy_source_stb -@200 --PHYRx --> SRAM_WRITER -@28 -top.dut.sram_writer_sink_ack -top.dut.sram_writer_sink_eop -@22 -top.dut.sram_writer_sink_payload_d[31:0] -top.dut.sram_writer_sink_payload_error[3:0] -top.dut.sram_writer_sink_payload_last_be[3:0] -@28 -top.dut.sram_writer_sink_sop -top.dut.sram_writer_sink_stb -[pattern_trace] 1 -[pattern_trace] 0 diff --git a/liteeth/mac/test/preamble_tb.py b/liteeth/mac/test/preamble_tb.py deleted file mode 100644 index 85bd7e644..000000000 --- a/liteeth/mac/test/preamble_tb.py +++ /dev/null @@ -1,82 +0,0 @@ -from migen.fhdl.std import * - -from misoclib.ethmac.common import * -from misoclib.ethmac.preamble import * -from misoclib.ethmac.test.common import * - -preamble = [ - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5 -] - -payload = [ - 0x00, 0x0A, 0xE6, 0xF0, 0x05, 0xA3, 0x00, 0x12, - 0x34, 0x56, 0x78, 0x90, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x30, 0xB3, 0xFE, 0x00, 0x00, 0x80, 0x11, - 0x72, 0xBA, 0x0A, 0x00, 0x00, 0x03, 0x0A, 0x00, - 0x00, 0x02, 0x04, 0x00, 0x04, 0x00, 0x00, 0x1C, - 0x89, 0x4D, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, - 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 -] - -mux = { - "inserter": 0, - "checker": 1, - "both": 2 -} - -class TB(Module): - def __init__(self, random_level=50): - sm = self.submodules - sm.streamer = PacketStreamer(eth_description(8)) - sm.streamer_randomizer = AckRandomizer(eth_description(8), random_level) - sm.logger = PacketLogger(eth_description(8)) - sm.logger_randomizer = AckRandomizer(eth_description(8), random_level) - - self.comb += [ - self.streamer.source.connect(self.streamer_randomizer.sink), - self.logger_randomizer.source.connect(self.logger.sink) - ] - - sm.preamble_inserter = PreambleInserter(8) - sm.preamble_checker = PreambleChecker(8) - - self.mux = Signal(2) - self.comb += [ - If(self.mux == mux["inserter"], - self.streamer_randomizer.source.connect(self.preamble_inserter.sink), - self.preamble_inserter.source.connect(self.logger_randomizer.sink) - ).Elif(self.mux == mux["checker"], - self.streamer_randomizer.source.connect(self.preamble_checker.sink), - self.preamble_checker.source.connect(self.logger_randomizer.sink) - ).Elif(self.mux == mux["both"], - self.streamer_randomizer.source.connect(self.preamble_inserter.sink), - self.preamble_inserter.source.connect(self.preamble_checker.sink), - self.preamble_checker.source.connect(self.logger_randomizer.sink) - ) - ] - def gen_simulation(self, selfp): - selfp.mux = mux["inserter"] - print("streamer --> preamble_inserter --> logger:") - self.streamer.send(Packet(payload)) - yield from self.logger.receive() - s, l, e = check(preamble+payload, self.logger.packet) - print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e)) - - selfp.mux = mux["checker"] - print("streamer --> preamble_checker --> logger:") - self.streamer.send(Packet(preamble+payload)) - yield from self.logger.receive() - s, l, e = check(payload, self.logger.packet) - print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e)) - - selfp.mux = mux["both"] - print("streamer --> preamble_inserter --> preamble_checker --> logger:") - self.streamer.send(Packet(payload)) - yield from self.logger.receive() - s, l, e = check(payload, self.logger.packet) - print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e)) - -if __name__ == "__main__": - from migen.sim.generic import run_simulation - run_simulation(TB(), ncycles=1000, vcd_name="my.vcd") diff --git a/liteeth/phy/gmii.py b/liteeth/phy/gmii.py index c1b8243d7..703f3c6c3 100644 --- a/liteeth/phy/gmii.py +++ b/liteeth/phy/gmii.py @@ -1,11 +1,6 @@ -from migen.fhdl.std import * -from migen.flow.actor import Sink, Source -from migen.bank.description import * -from migen.genlib.resetsync import AsyncResetSynchronizer +from liteeth.common import * -from liteethernet.common import * - -class GMIIPHYTX(Module): +class LiteEthPHYGMIITX(Module): def __init__(self, pads): self.sink = sink = Sink(eth_description(8)) ### @@ -16,7 +11,7 @@ class GMIIPHYTX(Module): ] self.comb += sink.ack.eq(1) -class GMIIPHYRX(Module): +class LiteEthPHYGMIIRX(Module): def __init__(self, pads): self.source = source = Source(eth_description(8)) ### @@ -38,7 +33,7 @@ class GMIIPHYRX(Module): # CRG is the only Xilinx specific module. # TODO: use generic code or add support for others vendors -class GMIIPHYCRG(Module, AutoCSR): +class LiteEthPHYGMIICRG(Module, AutoCSR): def __init__(self, clock_pads, pads): self._reset = CSRStorage() ### @@ -61,10 +56,10 @@ class GMIIPHYCRG(Module, AutoCSR): AsyncResetSynchronizer(self.cd_eth_rx, reset), ] -class GMIIPHY(Module, AutoCSR): +class LiteEthPHYMII(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.submodules.crg = LiteEthPHYGMIICRG(clock_pads, pads) + self.submodules.tx = RenameClockDomains(LiteEthPHYGMIITX(pads), "eth_tx") + self.submodules.rx = RenameClockDomains(LiteEthPHYGMIIRX(pads), "eth_rx") self.sink, self.source = self.tx.sink, self.rx.source diff --git a/liteeth/phy/loopback.py b/liteeth/phy/loopback.py index 04a51d07e..b4edb1651 100644 --- a/liteeth/phy/loopback.py +++ b/liteeth/phy/loopback.py @@ -1,11 +1,6 @@ -from migen.fhdl.std import * -from migen.flow.actor import Sink, Source -from migen.bank.description import * -from migen.genlib.record import * +from liteeth.common import * -from liteethernet.common import * - -class LoopbackPHYCRG(Module, AutoCSR): +class LiteEthPHYLoopbackCRG(Module, AutoCSR): def __init__(self): self._reset = CSRStorage() ### @@ -22,10 +17,10 @@ class LoopbackPHYCRG(Module, AutoCSR): self.cd_eth_tx.rst.eq(reset) ] -class LoopbackPHY(Module, AutoCSR): +class LiteEthPHYLoopback(Module, AutoCSR): def __init__(self): self.dw = 8 - self.submodules.crg = LoopbackPHYCRG() + self.submodules.crg = LiteEthLoopbackPHYCRG() 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/liteeth/phy/mii.py b/liteeth/phy/mii.py index a58b52b5d..8d6d19c79 100644 --- a/liteeth/phy/mii.py +++ b/liteeth/phy/mii.py @@ -1,12 +1,6 @@ -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 liteeth.common import * -from liteethernet.common import * - -class MIIPHYTX(Module): +class LiteEthPHYMIITX(Module): def __init__(self, pads): self.sink = sink = Sink(eth_description(8)) ### @@ -43,7 +37,7 @@ class MIIPHYTX(Module): ) ) -class MIIPHYRX(Module): +class LiteEthPHYMIIRX(Module): def __init__(self, pads): self.source = source = Source(eth_description(8)) ### @@ -95,7 +89,7 @@ class MIIPHYRX(Module): NextState("LOAD_LO") ) -class MIIPHYCRG(Module, AutoCSR): +class LiteEthPHYMIICRG(Module, AutoCSR): def __init__(self, clock_pads, pads): self._reset = CSRStorage() ### @@ -113,10 +107,10 @@ class MIIPHYCRG(Module, AutoCSR): AsyncResetSynchronizer(self.cd_eth_rx, reset), ] -class MIIPHY(Module, AutoCSR): +class LiteEthPHYMII(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.submodules.crg = LiteEthPHYMIICRG(clock_pads, pads) + self.submodules.tx = RenameClockDomains(LiteEthPHYMIITX(pads), "eth_tx") + self.submodules.rx = RenameClockDomains(LiteEthPHYMIIRX(pads), "eth_rx") self.sink, self.source = self.tx.sink, self.rx.source diff --git a/liteeth/test/Makefile b/liteeth/test/Makefile new file mode 100644 index 000000000..774146199 --- /dev/null +++ b/liteeth/test/Makefile @@ -0,0 +1,13 @@ +LEDIR = ../../ +PYTHON = python3 + +CMD = PYTHONPATH=$(MSCDIR) $(PYTHON) + +mac_crc_tb: + $(CMD) mac_crc_tb.py + +mac_preamble_tb: + $(CMD) mac_preamble_preamble_tb.py + +ethmac_tb: + $(CMD) ethmac_tb.py diff --git a/liteeth/mac/test/__init__.py b/liteeth/test/__init__.py similarity index 100% rename from liteeth/mac/test/__init__.py rename to liteeth/test/__init__.py diff --git a/liteeth/mac/test/common.py b/liteeth/test/common.py similarity index 100% rename from liteeth/mac/test/common.py rename to liteeth/test/common.py diff --git a/liteeth/mac/test/ethmac_tb.py b/liteeth/test/mac_core_tb.py similarity index 100% rename from liteeth/mac/test/ethmac_tb.py rename to liteeth/test/mac_core_tb.py diff --git a/liteeth/test/mac_wishbone_tb.py b/liteeth/test/mac_wishbone_tb.py new file mode 100644 index 000000000..1e4dbf1fe --- /dev/null +++ b/liteeth/test/mac_wishbone_tb.py @@ -0,0 +1,123 @@ +from migen.fhdl.std import * +from migen.bus import wishbone +from migen.bus.transactions import * +from migen.sim.generic import run_simulation + +from misoclib.ethmac import EthMAC +from misoclib.ethmac.phy import loopback + +from misoclib.ethmac.test.common import * + +class WishboneMaster: + def __init__(self, obj): + self.obj = obj + self.dat = 0 + + def write(self, adr, dat): + self.obj.cyc = 1 + self.obj.stb = 1 + self.obj.adr = adr + self.obj.we = 1 + self.obj.sel = 0xF + self.obj.dat_w = dat + while self.obj.ack == 0: + yield + self.obj.cyc = 0 + self.obj.stb = 0 + yield + + def read(self, adr): + self.obj.cyc = 1 + self.obj.stb = 1 + self.obj.adr = adr + self.obj.we = 0 + self.obj.sel = 0xF + self.obj.dat_w = 0 + while self.obj.ack == 0: + yield + self.dat = self.obj.dat_r + self.obj.cyc = 0 + self.obj.stb = 0 + yield + +class SRAMReaderDriver: + def __init__(self, obj): + self.obj = obj + + def start(self, slot, length): + self.obj._slot.storage = slot + self.obj._length.storage = length + self.obj._start.re = 1 + yield + self.obj._start.re = 0 + yield + + def wait_done(self): + while self.obj.ev.done.pending == 0: + yield + + def clear_done(self): + self.obj.ev.done.clear = 1 + yield + self.obj.ev.done.clear = 0 + yield + +class TB(Module): + def __init__(self): + self.submodules.ethphy = loopback.LoopbackPHY() + self.submodules.ethmac = EthMAC(phy=self.ethphy, with_hw_preamble_crc=True) + + # use sys_clk for each clock_domain + 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_rx.rst.eq(ResetSignal()), + self.cd_eth_tx.clk.eq(ClockSignal()), + self.cd_eth_tx.rst.eq(ResetSignal()), + ] + + def gen_simulation(self, selfp): + selfp.cd_eth_rx.rst = 1 + selfp.cd_eth_tx.rst = 1 + yield + selfp.cd_eth_rx.rst = 0 + selfp.cd_eth_tx.rst = 0 + + wishbone_master = WishboneMaster(selfp.ethmac.bus) + sram_reader_driver = SRAMReaderDriver(selfp.ethmac.sram_reader) + + sram_writer_slots_offset = [0x000, 0x200] + sram_reader_slots_offset = [0x400, 0x600] + + length = 1500+2 + + tx_payload = [seed_to_data(i, True) % 0xFF for i in range(length)] + [0, 0, 0, 0] + + errors = 0 + + for slot in range(2): + print("slot {}:".format(slot)) + # fill tx memory + for i in range(length//4+1): + dat = int.from_bytes(tx_payload[4*i:4*(i+1)], "big") + yield from wishbone_master.write(sram_reader_slots_offset[slot]+i, dat) + + # send tx payload & wait + yield from sram_reader_driver.start(slot, length) + yield from sram_reader_driver.wait_done() + yield from sram_reader_driver.clear_done() + + # get rx payload (loopback on PHY Model) + rx_payload = [] + for i in range(length//4+1): + yield from wishbone_master.read(sram_writer_slots_offset[slot]+i) + dat = wishbone_master.dat + rx_payload += list(dat.to_bytes(4, byteorder='big')) + + # check results + s, l, e = check(tx_payload[:length], rx_payload[:min(length, len(rx_payload))]) + print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e)) + +if __name__ == "__main__": + run_simulation(TB(), vcd_name="my.vcd")