+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
-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")
-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)
-
-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"):
+from liteeth.common import *
+from liteeth.mac.common import *
+from liteeth.mac import preamble, crc, last_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"})
-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
@DecorateModule(InsertReset)
@DecorateModule(InsertCE)
-class CRC32(Module):
+class LiteEthMACCRC32(Module):
"""IEEE 802.3 CRC
Implement an IEEE 802.3 CRC generator/checker.
###
- 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 += [
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.
)
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.
)
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)
-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))
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))
-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))
)
)
-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))
-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 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))
+from liteeth.common import *
+from liteeth.mac.common import *
+
+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)
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
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
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
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
-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
+++ /dev/null
-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
+++ /dev/null
-import random, copy
-
-from migen.fhdl.std import *
-from migen.flow.actor import Sink, Source
-from migen.genlib.record import *
-
-from misoclib.ethmac.common import *
-
-def seed_to_data(seed, random=True):
- if random:
- return (seed * 0x31415979 + 1) & 0xffffffff
- else:
- return seed
-
-def check(p1, p2):
- p1 = copy.deepcopy(p1)
- p2 = copy.deepcopy(p2)
- if isinstance(p1, int):
- return 0, 1, int(p1 != p2)
- else:
- if len(p1) >= len(p2):
- ref, res = p1, p2
- else:
- ref, res = p2, p1
- shift = 0
- while((ref[0] != res[0]) and (len(res)>1)):
- res.pop(0)
- shift += 1
- length = min(len(ref), len(res))
- errors = 0
- for i in range(length):
- if ref.pop(0) != res.pop(0):
- errors += 1
- return shift, length, errors
-
-def randn(max_n):
- return random.randint(0, max_n-1)
-
-class Packet(list):
- def __init__(self, init=[]):
- self.ongoing = False
- self.done = False
- for data in init:
- self.append(data)
-
-class PacketStreamer(Module):
- def __init__(self, description):
- self.source = Source(description)
- ###
- self.packets = []
- self.packet = Packet()
- self.packet.done = 1
-
- def send(self, packet):
- packet = copy.deepcopy(packet)
- self.packets.append(packet)
-
- def do_simulation(self, selfp):
- if len(self.packets) and self.packet.done:
- self.packet = self.packets.pop(0)
- if not self.packet.ongoing and not self.packet.done:
- selfp.source.stb = 1
- selfp.source.sop = 1
- selfp.source.d = self.packet.pop(0)
- self.packet.ongoing = True
- elif selfp.source.stb == 1 and selfp.source.ack == 1:
- selfp.source.sop = 0
- selfp.source.eop = (len(self.packet) == 1)
- if len(self.packet) > 0:
- selfp.source.stb = 1
- selfp.source.d = self.packet.pop(0)
- else:
- self.packet.done = 1
- selfp.source.stb = 0
-
-class PacketLogger(Module):
- def __init__(self, description):
- self.sink = Sink(description)
- ###
- self.packet = Packet()
-
- def receive(self):
- self.packet.done = 0
- while self.packet.done == 0:
- yield
-
- def do_simulation(self, selfp):
- selfp.sink.ack = 1
- if selfp.sink.stb == 1 and selfp.sink.sop == 1:
- self.packet = Packet()
- self.packet.append(selfp.sink.d)
- elif selfp.sink.stb:
- self.packet.append(selfp.sink.d)
- if selfp.sink.stb == 1 and selfp.sink.eop == 1:
- self.packet.done = True
-
-class AckRandomizer(Module):
- def __init__(self, description, level=0):
- self.level = level
-
- self.sink = Sink(description)
- self.source = Source(description)
-
- self.run = Signal()
-
- self.comb += \
- If(self.run,
- Record.connect(self.sink, self.source)
- ).Else(
- self.source.stb.eq(0),
- self.sink.ack.eq(0),
- )
-
- def do_simulation(self, selfp):
- n = randn(100)
- if n < self.level:
- selfp.run = 0
- else:
- selfp.run = 1
-
+++ /dev/null
-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")
+++ /dev/null
-[*]
-[*] 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
+++ /dev/null
-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")
+++ /dev/null
-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")
-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))
###
]
self.comb += sink.ack.eq(1)
-class GMIIPHYRX(Module):
+class LiteEthPHYGMIIRX(Module):
def __init__(self, pads):
self.source = source = Source(eth_description(8))
###
# 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()
###
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
-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()
###
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)
-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))
###
)
)
-class MIIPHYRX(Module):
+class LiteEthPHYMIIRX(Module):
def __init__(self, pads):
self.source = source = Source(eth_description(8))
###
NextState("LOAD_LO")
)
-class MIIPHYCRG(Module, AutoCSR):
+class LiteEthPHYMIICRG(Module, AutoCSR):
def __init__(self, clock_pads, pads):
self._reset = CSRStorage()
###
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
--- /dev/null
+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
--- /dev/null
+import random, copy
+
+from migen.fhdl.std import *
+from migen.flow.actor import Sink, Source
+from migen.genlib.record import *
+
+from misoclib.ethmac.common import *
+
+def seed_to_data(seed, random=True):
+ if random:
+ return (seed * 0x31415979 + 1) & 0xffffffff
+ else:
+ return seed
+
+def check(p1, p2):
+ p1 = copy.deepcopy(p1)
+ p2 = copy.deepcopy(p2)
+ if isinstance(p1, int):
+ return 0, 1, int(p1 != p2)
+ else:
+ if len(p1) >= len(p2):
+ ref, res = p1, p2
+ else:
+ ref, res = p2, p1
+ shift = 0
+ while((ref[0] != res[0]) and (len(res)>1)):
+ res.pop(0)
+ shift += 1
+ length = min(len(ref), len(res))
+ errors = 0
+ for i in range(length):
+ if ref.pop(0) != res.pop(0):
+ errors += 1
+ return shift, length, errors
+
+def randn(max_n):
+ return random.randint(0, max_n-1)
+
+class Packet(list):
+ def __init__(self, init=[]):
+ self.ongoing = False
+ self.done = False
+ for data in init:
+ self.append(data)
+
+class PacketStreamer(Module):
+ def __init__(self, description):
+ self.source = Source(description)
+ ###
+ self.packets = []
+ self.packet = Packet()
+ self.packet.done = 1
+
+ def send(self, packet):
+ packet = copy.deepcopy(packet)
+ self.packets.append(packet)
+
+ def do_simulation(self, selfp):
+ if len(self.packets) and self.packet.done:
+ self.packet = self.packets.pop(0)
+ if not self.packet.ongoing and not self.packet.done:
+ selfp.source.stb = 1
+ selfp.source.sop = 1
+ selfp.source.d = self.packet.pop(0)
+ self.packet.ongoing = True
+ elif selfp.source.stb == 1 and selfp.source.ack == 1:
+ selfp.source.sop = 0
+ selfp.source.eop = (len(self.packet) == 1)
+ if len(self.packet) > 0:
+ selfp.source.stb = 1
+ selfp.source.d = self.packet.pop(0)
+ else:
+ self.packet.done = 1
+ selfp.source.stb = 0
+
+class PacketLogger(Module):
+ def __init__(self, description):
+ self.sink = Sink(description)
+ ###
+ self.packet = Packet()
+
+ def receive(self):
+ self.packet.done = 0
+ while self.packet.done == 0:
+ yield
+
+ def do_simulation(self, selfp):
+ selfp.sink.ack = 1
+ if selfp.sink.stb == 1 and selfp.sink.sop == 1:
+ self.packet = Packet()
+ self.packet.append(selfp.sink.d)
+ elif selfp.sink.stb:
+ self.packet.append(selfp.sink.d)
+ if selfp.sink.stb == 1 and selfp.sink.eop == 1:
+ self.packet.done = True
+
+class AckRandomizer(Module):
+ def __init__(self, description, level=0):
+ self.level = level
+
+ self.sink = Sink(description)
+ self.source = Source(description)
+
+ self.run = Signal()
+
+ self.comb += \
+ If(self.run,
+ Record.connect(self.sink, self.source)
+ ).Else(
+ self.source.stb.eq(0),
+ self.sink.ack.eq(0),
+ )
+
+ def do_simulation(self, selfp):
+ n = randn(100)
+ if n < self.level:
+ selfp.run = 0
+ else:
+ selfp.run = 1
+
--- /dev/null
+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")
--- /dev/null
+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")