new Ethernet MAC
authorFlorent Kermarec <florent@enjoy-digital.fr>
Fri, 21 Nov 2014 00:47:11 +0000 (16:47 -0800)
committerSebastien Bourdeauducq <sb@m-labs.hk>
Fri, 21 Nov 2014 00:47:22 +0000 (16:47 -0800)
31 files changed:
misoclib/ethmac/__init__.py [new file with mode: 0644]
misoclib/ethmac/last_be.py [new file with mode: 0644]
misoclib/ethmac/phys/gmii.py [new file with mode: 0644]
misoclib/ethmac/phys/loopback.py [new file with mode: 0644]
misoclib/ethmac/phys/mii.py [new file with mode: 0644]
misoclib/ethmac/preamble.py [new file with mode: 0644]
misoclib/ethmac/sram.py [new file with mode: 0644]
misoclib/ethmac/std.py [new file with mode: 0644]
misoclib/ethmac/test/Makefile [new file with mode: 0644]
misoclib/ethmac/test/__init__.py [new file with mode: 0644]
misoclib/ethmac/test/crc_tb.py [new file with mode: 0644]
misoclib/ethmac/test/ethmac_tb.py [new file with mode: 0644]
misoclib/ethmac/test/preamble_tb.py [new file with mode: 0644]
misoclib/minimac3/__init__.py [deleted file]
misoclib/mxcrg/__init__.py
software/bios/boot.c
software/bios/main.c
software/include/hw/ethmac_mem.h [new file with mode: 0644]
software/include/hw/flags.h
software/include/hw/minimac_mem.h [deleted file]
software/libnet/microudp.c
software/libnet/tftp.c
targets/kc705.py
targets/mlabs_video.py
verilog/minimac3/minimac3.v [deleted file]
verilog/minimac3/minimac3_memory.v [deleted file]
verilog/minimac3/minimac3_rx.v [deleted file]
verilog/minimac3/minimac3_sync.v [deleted file]
verilog/minimac3/minimac3_tx.v [deleted file]
verilog/minimac3/psync.v [deleted file]
verilog/mxcrg/mxcrg.v

diff --git a/misoclib/ethmac/__init__.py b/misoclib/ethmac/__init__.py
new file mode 100644 (file)
index 0000000..73b1a17
--- /dev/null
@@ -0,0 +1,110 @@
+# This file is Copyright (c) 2014 Florent Kermarrec <florent@enjoy-digital.fr>
+# License: BSD
+
+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.std 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)
+
+               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)]
+                       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":
+                       raise NotImplementedError
+
+               elif interface == "expose":
+                       # expose pipelines endpoints
+                       self.sink = tx_pipeline.sink
+                       self.source = rx_pipeline.source
+
+               else:
+                       raise ValueError("EthMAC only supports Wishbone, LASMI or expose interfaces")
diff --git a/misoclib/ethmac/last_be.py b/misoclib/ethmac/last_be.py
new file mode 100644 (file)
index 0000000..e7fbf2a
--- /dev/null
@@ -0,0 +1,37 @@
+from migen.fhdl.std import *
+from migen.genlib.record import *
+from migen.flow.actor import Sink, Source
+
+from misoclib.ethmac.std import *
+
+class TXLastBE(Module):
+       def __init__(self, d_w):
+               self.sink = sink = Sink(eth_description(d_w))
+               self.source = source = Source(eth_description(d_w))
+               ###
+               ongoing = Signal()
+               self.sync += \
+                       If(self.sink.stb & self.sink.ack,
+                               If(sink.sop,
+                                       ongoing.eq(1)
+                               ).Elif(sink.last_be,
+                                       ongoing.eq(0)
+                               )
+                       )
+               self.comb += [
+                       Record.connect(self.sink, self.source),
+                       self.source.eop.eq(self.sink.last_be),
+                       self.source.stb.eq(self.sink.stb & (self.sink.sop | ongoing))
+               ]
+
+class RXLastBE(Module):
+       def __init__(self, d_w):
+               self.sink = sink = Sink(eth_description(d_w))
+               self.source = source = Source(eth_description(d_w))
+               ###
+               fake = Signal() # to use RenameClockDomain
+               self.sync += fake.eq(1)
+               self.comb += [
+                       Record.connect(self.sink, self.source),
+                       self.source.last_be.eq(self.sink.eop)
+               ]
diff --git a/misoclib/ethmac/phys/gmii.py b/misoclib/ethmac/phys/gmii.py
new file mode 100644 (file)
index 0000000..f4a8210
--- /dev/null
@@ -0,0 +1,71 @@
+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.std 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/misoclib/ethmac/phys/loopback.py b/misoclib/ethmac/phys/loopback.py
new file mode 100644 (file)
index 0000000..9e8d83c
--- /dev/null
@@ -0,0 +1,32 @@
+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.std 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/misoclib/ethmac/phys/mii.py b/misoclib/ethmac/phys/mii.py
new file mode 100644 (file)
index 0000000..5dba08c
--- /dev/null
@@ -0,0 +1,123 @@
+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.std 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/misoclib/ethmac/preamble.py b/misoclib/ethmac/preamble.py
new file mode 100644 (file)
index 0000000..db693b4
--- /dev/null
@@ -0,0 +1,145 @@
+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 misoclib.ethmac.std import *
+
+class PreambleInserter(Module):
+       def __init__(self, d_w):
+               self.sink = Sink(eth_description(d_w))
+               self.source = Source(eth_description(d_w))
+
+               ###
+
+               preamble = Signal(64, reset=eth_preamble)
+               cnt_max = (64//d_w)-1
+               cnt = Signal(max=cnt_max+1)
+               clr_cnt = Signal()
+               inc_cnt = Signal()
+
+               self.sync += \
+                       If(clr_cnt,
+                               cnt.eq(0)
+                       ).Elif(inc_cnt,
+                               cnt.eq(cnt+1)
+                       )
+
+               fsm = FSM(reset_state="IDLE")
+               self.submodules += fsm
+               fsm.act("IDLE",
+                       self.sink.ack.eq(1),
+                       clr_cnt.eq(1),
+                       If(self.sink.stb & self.sink.sop,
+                               self.sink.ack.eq(0),
+                               NextState("INSERT"),
+                       )
+               )
+               fsm.act("INSERT",
+                       self.source.stb.eq(1),
+                       self.source.sop.eq(cnt==0),
+                       chooser(preamble, cnt, self.source.d),
+                       If(cnt == cnt_max,
+                               If(self.source.ack, NextState("COPY"))
+                       ).Else(
+                               inc_cnt.eq(self.source.ack)
+                       )
+               )
+               fsm.act("COPY",
+                       Record.connect(self.sink, self.source),
+                       self.source.sop.eq(0),
+
+                       If(self.sink.stb & self.sink.eop & self.source.ack,
+                               NextState("IDLE"),
+                       )
+               )
+
+class PreambleChecker(Module):
+       def __init__(self, d_w):
+               self.sink = Sink(eth_description(d_w))
+               self.source = Source(eth_description(d_w))
+
+               ###
+
+               preamble = Signal(64, reset=eth_preamble)
+               cnt_max = (64//d_w)-1
+               cnt = Signal(max=cnt_max+1)
+               clr_cnt = Signal()
+               inc_cnt = Signal()
+
+               self.sync += \
+                       If(clr_cnt,
+                               cnt.eq(0)
+                       ).Elif(inc_cnt,
+                               cnt.eq(cnt+1)
+                       )
+
+               discard = Signal()
+               clr_discard = Signal()
+               set_discard = Signal()
+
+               self.sync += \
+                       If(clr_discard,
+                               discard.eq(0)
+                       ).Elif(set_discard,
+                               discard.eq(1)
+                       )
+
+               sop = Signal()
+               clr_sop = Signal()
+               set_sop = Signal()
+               self.sync += \
+                       If(clr_sop,
+                               sop.eq(0)
+                       ).Elif(set_sop,
+                               sop.eq(1)
+                       )
+
+               ref = Signal(d_w)
+               match = Signal()
+               self.comb += [
+                       chooser(preamble, cnt, ref),
+                       match.eq(self.sink.d == ref)
+               ]
+
+               fsm = FSM(reset_state="IDLE")
+               self.submodules += fsm
+
+               fsm.act("IDLE",
+                       self.sink.ack.eq(1),
+                       clr_cnt.eq(1),
+                       clr_discard.eq(1),
+                       If(self.sink.stb & self.sink.sop,
+                               clr_cnt.eq(0),
+                               inc_cnt.eq(1),
+                               clr_discard.eq(0),
+                               set_discard.eq(~match),
+                               NextState("CHECK"),
+                       )
+               )
+               fsm.act("CHECK",
+                       self.sink.ack.eq(1),
+                       If(self.sink.stb,
+                               set_discard.eq(~match),
+                               If(cnt == cnt_max,
+                                       If(discard | (~match),
+                                               NextState("IDLE")
+                                       ).Else(
+                                               set_sop.eq(1),
+                                               NextState("COPY")
+                                       )
+                               ).Else(
+                                       inc_cnt.eq(1)
+                               )
+                       )
+               )
+               fsm.act("COPY",
+                       Record.connect(self.sink, self.source),
+                       self.source.sop.eq(sop),
+                       clr_sop.eq(self.source.stb & self.source.ack),
+
+                       If(self.source.stb & self.source.eop & self.source.ack,
+                               NextState("IDLE"),
+                       )
+               )
diff --git a/misoclib/ethmac/sram.py b/misoclib/ethmac/sram.py
new file mode 100644 (file)
index 0000000..5160a8f
--- /dev/null
@@ -0,0 +1,251 @@
+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 misoclib.ethmac.std import *
+
+class SRAMWriter(Module, AutoCSR):
+       def __init__(self, depth, nslots=2):
+               self.sink = sink = Sink(eth_description(32))
+               self.crc_error = Signal()
+
+               slotbits = max(log2_int(nslots), 1)
+               lengthbits = log2_int(depth*4) # length in bytes
+
+               self._slot = CSRStatus(slotbits)
+               self._length = CSRStatus(lengthbits)
+
+               self.submodules.ev = EventManager()
+               self.ev.available = EventSourceLevel()
+               self.ev.finalize()
+
+               ###
+
+       # packet dropped if no slot available
+               sink.ack.reset = 1
+
+       # length computation
+               cnt = Signal(lengthbits)
+               clr_cnt = Signal()
+               inc_cnt = Signal()
+               inc_val = Signal(3)
+               self.comb += \
+                       If(sink.last_be[3],
+                               inc_val.eq(1)
+                       ).Elif(sink.last_be[2],
+                               inc_val.eq(2)
+                       ).Elif(sink.last_be[1],
+                               inc_val.eq(3)
+                       ).Else(
+                               inc_val.eq(4)
+                       )
+               self.sync += \
+                       If(clr_cnt,
+                               cnt.eq(0)
+                       ).Elif(inc_cnt,
+                               cnt.eq(cnt+inc_val)
+                       )
+
+       # slot computation
+               slot = Signal(slotbits)
+               inc_slot = Signal()
+               self.sync += \
+                       If(inc_slot,
+                               If(slot == nslots-1,
+                                       slot.eq(0),
+                               ).Else(
+                                       slot.eq(slot+1)
+                               )
+                       )
+               ongoing = Signal()
+               discard = Signal()
+
+       # status fifo
+               fifo = SyncFIFO([("slot", slotbits), ("length", lengthbits)], nslots)
+               self.submodules += fifo
+
+       # fsm
+               fsm = FSM(reset_state="IDLE")
+               self.submodules += fsm
+
+               fsm.act("IDLE",
+                       inc_cnt.eq(sink.stb),
+                       If(sink.stb & sink.sop,
+                               ongoing.eq(1),
+                               If(fifo.writable,
+                                       NextState("WRITE")
+                               )
+                       )
+               )
+               fsm.act("WRITE",
+                       inc_cnt.eq(sink.stb),
+                       ongoing.eq(1),
+                       If(sink.stb & sink.eop,
+                               If((sink.error & sink.last_be) != 0,
+                                       NextState("DISCARD")
+                               ).Else(
+                                       NextState("TERMINATE")
+                               )
+                       )
+               )
+               fsm.act("DISCARD",
+                       clr_cnt.eq(1),
+                       NextState("IDLE")
+               )
+               fsm.act("TERMINATE",
+                       clr_cnt.eq(1),
+                       inc_slot.eq(1),
+                       fifo.we.eq(1),
+                       fifo.din.slot.eq(slot),
+                       fifo.din.length.eq(cnt),
+                       NextState("IDLE")
+               )
+
+               self.comb += [
+                       fifo.re.eq(self.ev.available.clear),
+                       self.ev.available.trigger.eq(fifo.readable),
+                       self._slot.status.eq(fifo.dout.slot),
+                       self._length.status.eq(fifo.dout.length),
+               ]
+
+       # memory
+               mems = [None]*nslots
+               ports = [None]*nslots
+               for n in range(nslots):
+                       mems[n] = Memory(32, depth)
+                       ports[n] = mems[n].get_port(write_capable=True)
+                       self.specials += ports[n]
+               self.mems = mems
+
+               cases = {}
+               for n, port in enumerate(ports):
+                       cases[n] = [
+                               ports[n].adr.eq(cnt[2:]),
+                               ports[n].dat_w.eq(sink.d),
+                               If(sink.stb & ongoing,
+                                       ports[n].we.eq(0xf)
+                               )
+                       ]
+               self.comb += Case(slot, cases)
+
+
+class SRAMReader(Module, AutoCSR):
+       def __init__(self, depth, nslots=2):
+               self.source = source = Source(eth_description(32))
+
+               slotbits = max(log2_int(nslots), 1)
+               lengthbits = log2_int(depth*4) # length in bytes
+               self.lengthbits = lengthbits
+
+               self._start = CSR()
+               self._ready = CSRStatus()
+               self._slot = CSRStorage(slotbits)
+               self._length = CSRStorage(lengthbits)
+
+               self.submodules.ev = EventManager()
+               self.ev.done = EventSourcePulse()
+               self.ev.finalize()
+
+               ###
+
+       # command fifo
+               fifo = SyncFIFO([("slot", slotbits), ("length", lengthbits)], nslots)
+               self.submodules += fifo
+               self.comb += [
+                       fifo.we.eq(self._start.re),
+                       fifo.din.slot.eq(self._slot.storage),
+                       fifo.din.length.eq(self._length.storage),
+                       self._ready.status.eq(fifo.writable)
+               ]
+
+       # length computation
+               cnt = Signal(lengthbits)
+               clr_cnt = Signal()
+               inc_cnt = Signal()
+
+               self.sync += \
+                       If(clr_cnt,
+                               cnt.eq(0)
+                       ).Elif(inc_cnt,
+                               cnt.eq(cnt+4)
+                       )
+
+       # fsm
+               first = Signal()
+               last  = Signal()
+               last_d = Signal()
+
+               fsm = FSM(reset_state="IDLE")
+               self.submodules += fsm
+
+               fsm.act("IDLE",
+                       clr_cnt.eq(1),
+                       If(fifo.readable,
+                               NextState("CHECK")
+                       )
+               )
+               fsm.act("CHECK",
+                       If(~last_d,
+                               NextState("SEND"),
+                       ).Else(
+                               NextState("END"),
+                       )
+               )
+               length_lsb = fifo.dout.length[0:2]
+               fsm.act("SEND",
+                       source.stb.eq(1),
+                       source.sop.eq(first),
+                       source.eop.eq(last),
+                       If(last,
+                               If(length_lsb == 3,
+                                       source.last_be.eq(0b0010)
+                               ).Elif(length_lsb == 2,
+                                       source.last_be.eq(0b0100)
+                               ).Elif(length_lsb == 1,
+                                       source.last_be.eq(0b1000)
+                               ).Else(
+                                       source.last_be.eq(0b0001)
+                               )
+                       ),
+                       If(source.ack,
+                               inc_cnt.eq(~last),
+                               NextState("CHECK")
+                       )
+               )
+               fsm.act("END",
+                       fifo.re.eq(1),
+                       self.ev.done.trigger.eq(1),
+                       NextState("IDLE")
+               )
+
+       # first/last computation
+               self.sync += [
+                       If(fsm.ongoing("IDLE"),
+                               first.eq(1)
+                       ).Elif(source.stb & source.ack,
+                               first.eq(0)
+                       )
+               ]
+               self.comb += last.eq(cnt+4 >= fifo.dout.length)
+               self.sync += last_d.eq(last)
+
+       # memory
+               rd_slot = fifo.dout.slot
+
+               mems = [None]*nslots
+               ports = [None]*nslots
+               for n in range(nslots):
+                       mems[n] = Memory(32, depth)
+                       ports[n] = mems[n].get_port()
+                       self.specials += ports[n]
+               self.mems = mems
+
+               cases = {}
+               for n, port in enumerate(ports):
+                       self.comb += ports[n].adr.eq(cnt[2:])
+                       cases[n] = [source.d.eq(port.dat_r)]
+               self.comb += Case(rd_slot, cases)
diff --git a/misoclib/ethmac/std.py b/misoclib/ethmac/std.py
new file mode 100644 (file)
index 0000000..5e5c129
--- /dev/null
@@ -0,0 +1,17 @@
+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):
+       parameters = {
+               "packetized": True
+       }
+       layout = [
+               ("d", dw),
+               ("last_be", dw//8),
+               ("error", dw//8)
+       ]
+       return EndpointDescription(layout, parameters)
diff --git a/misoclib/ethmac/test/Makefile b/misoclib/ethmac/test/Makefile
new file mode 100644 (file)
index 0000000..55d28e1
--- /dev/null
@@ -0,0 +1,13 @@
+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/misoclib/ethmac/test/__init__.py b/misoclib/ethmac/test/__init__.py
new file mode 100644 (file)
index 0000000..f3ad952
--- /dev/null
@@ -0,0 +1,53 @@
+import random
+from migen.fhdl.std import *
+from migen.flow.actor import Sink, Source
+
+from misoclib.ethmac.std import *
+
+class PacketStreamer(Module):
+       def __init__(self, data):
+               self.source = Source(eth_description(8))
+               self.data = data
+
+       def gen_simulation(self, selfp):
+               for n, data in enumerate(self.data):
+                       selfp.source.stb = 1
+                       selfp.source.sop = (n == 0)
+                       selfp.source.eop = (n == len(self.data)-1)
+                       selfp.source.payload.d = data
+                       yield
+                       while (selfp.source.ack == 0):
+                               yield
+                       selfp.source.stb = 0
+                       while (bool(random.getrandbits(1)) == 0):
+                               yield
+
+class PacketLogger(Module):
+       def __init__(self):
+               self.sink = Sink(eth_description(8))
+               self.data = []
+
+       def do_simulation(self, selfp):
+               selfp.sink.ack = bool(random.getrandbits(1))
+               if selfp.sink.stb == 1 and selfp.sink.ack:
+                       self.data.append(selfp.sink.payload.d)
+
+def print_results(s, l1, l2):
+       def comp(l1, l2):
+               r = True
+               try:
+                       for i, val in enumerate(l1):
+                               if val != l2[i]:
+                                       print(s + " : val : %02X, exp : %02X" %(val, l2[i]))
+                                       r = False
+               except:
+                       r = False
+               return r
+
+       c = comp(l1, l2)
+       r = s + " "
+       if c:
+               r += "[OK]"
+       else:
+               r += "[KO]"
+       print(r)
diff --git a/misoclib/ethmac/test/crc_tb.py b/misoclib/ethmac/test/crc_tb.py
new file mode 100644 (file)
index 0000000..74fab28
--- /dev/null
@@ -0,0 +1,61 @@
+from migen.fhdl.std import *
+from migen.actorlib.crc import *
+
+from misoclib.ethmac.std import *
+
+from misoclib.ethmac.test import *
+
+frame_data = [
+       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
+]
+
+frame_crc = [
+       0x7A, 0xD5, 0x6B, 0xB3
+]
+
+class TB(Module):
+       def __init__(self):
+
+               sm = self.submodules
+
+       # Streamer (DATA) --> CRC32Inserter --> Logger (expect DATA + CRC)
+               sm.inserter_streamer = PacketStreamer(frame_data)
+               sm.crc32_inserter = CRC32Inserter(eth_description(8))
+               sm.inserter_logger = PacketLogger()
+               self.comb +=[
+                       self.inserter_streamer.source.connect(self.crc32_inserter.sink),
+                       self.crc32_inserter.source.connect(self.inserter_logger.sink),
+               ]
+
+       # Streamer (DATA + CRC) --> CRC32Checher --> Logger (except DATA + CRC + check)
+               sm.checker_streamer = PacketStreamer(frame_data+frame_crc)
+               sm.crc32_checker = CRC32Checker(eth_description(8))
+               sm.checker_logger = PacketLogger()
+               self.comb +=[
+                       self.checker_streamer.source.connect(self.crc32_checker.sink),
+                       self.crc32_checker.source.connect(self.checker_logger.sink),
+               ]
+
+       def gen_simulation(self, selfp):
+               for i in range(500):
+                       yield
+               inserter_reference = frame_data + frame_crc
+               inserter_generated = self.inserter_logger.data
+
+               checker_reference = frame_data
+               checker_generated = self.checker_logger.data
+
+               print_results("inserter", inserter_reference, inserter_generated)
+               print_results("checker", checker_reference, checker_generated)
+
+
+if __name__ == "__main__":
+       from migen.sim.generic import run_simulation
+       run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True)
diff --git a/misoclib/ethmac/test/ethmac_tb.py b/misoclib/ethmac/test/ethmac_tb.py
new file mode 100644 (file)
index 0000000..7a02f35
--- /dev/null
@@ -0,0 +1,134 @@
+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.phys import loopback
+
+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
+
+               payload = [i%0xFF for i in range(length)] + [0, 0, 0, 0]
+
+               errors = 0
+
+               for slot in range(2):
+                       # fill tx memory
+                       for i in range(length//4+1):
+                               dat = 0
+                               dat |= payload[4*i+0] << 24
+                               dat |= payload[4*i+1] << 16
+                               dat |= payload[4*i+2] << 8
+                               dat |= payload[4*i+3] << 0
+                               yield from wishbone_master.write(sram_reader_slots_offset[slot]+i, dat)
+
+                       # send tx data & 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 data (loopback on PHY Model)
+                       rx_dat = []
+                       for i in range(length//4+1):
+                               yield from wishbone_master.read(sram_writer_slots_offset[slot]+i)
+                               dat = wishbone_master.dat
+                               rx_dat.append((dat >> 24) & 0xFF)
+                               rx_dat.append((dat >> 16) & 0xFF)
+                               rx_dat.append((dat >> 8) & 0xFF)
+                               rx_dat.append((dat >> 0) & 0xFF)
+
+                       # check rx data
+                       for i in range(length):
+                               #print("%02x / %02x" %(rx_dat[i], payload[i]))
+                               if rx_dat[i] != payload[i]:
+                                       errors += 1
+
+               for i in range(200):
+                       yield
+               #print(selfp.ethmac.sram_reader._length.storage)
+
+               print("Errors : %d" %errors)
+
+if __name__ == "__main__":
+       run_simulation(TB(), ncycles=16000, vcd_name="my.vcd", keep_files=True)
diff --git a/misoclib/ethmac/test/preamble_tb.py b/misoclib/ethmac/test/preamble_tb.py
new file mode 100644 (file)
index 0000000..8fca916
--- /dev/null
@@ -0,0 +1,61 @@
+from migen.fhdl.std import *
+
+from misoclib.ethmac.std import *
+from misoclib.ethmac.preamble import *
+
+from misoclib.ethmac.test import *
+
+frame_preamble = [
+       0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5
+]
+
+frame_data = [
+       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
+]
+
+class TB(Module):
+       def __init__(self):
+
+               sm = self.submodules
+
+       # Streamer (DATA) --> PreambleInserter --> Logger (expect PREAMBLE + DATA)
+               sm.inserter_streamer = PacketStreamer(frame_data)
+               sm.preamble_inserter = PreambleInserter(8)
+               sm.inserter_logger = PacketLogger()
+               self.comb +=[
+                       self.inserter_streamer.source.connect(self.preamble_inserter.sink),
+                       self.preamble_inserter.source.connect(self.inserter_logger.sink),
+               ]
+
+       # Streamer (PREAMBLE + DATA) --> CRC32Checher --> Logger (except DATA + check)
+               sm.checker_streamer = PacketStreamer(frame_preamble + frame_data)               
+               sm.preamble_checker = PreambleChecker(8)
+               sm.checker_logger = PacketLogger()
+               self.comb +=[
+                       self.checker_streamer.source.connect(self.preamble_checker.sink),
+                       self.preamble_checker.source.connect(self.checker_logger.sink),
+               ]
+
+
+       def gen_simulation(self, selfp):
+               for i in range(500):
+                       yield
+               inserter_reference = frame_preamble + frame_data
+               inserter_generated = self.inserter_logger.data
+
+               checker_reference = frame_data
+               checker_generated = self.checker_logger.data
+
+               print_results("inserter", inserter_reference, inserter_generated)
+               print_results("checker", checker_reference, checker_generated)
+
+if __name__ == "__main__":
+       from migen.sim.generic import run_simulation
+       run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True)
diff --git a/misoclib/minimac3/__init__.py b/misoclib/minimac3/__init__.py
deleted file mode 100644 (file)
index ab6753a..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-from migen.bus import wishbone
-
-_count_width = 11
-
-class MiniMAC(Module, AutoCSR):
-       def __init__(self, pads):
-               # CPU interface
-               self._phy_reset = CSRStorage(reset=1)
-               self._rx_count_0 = CSRStatus(_count_width)
-               self._rx_count_1 = CSRStatus(_count_width)
-               self._tx_count = CSRStorage(_count_width, write_from_dev=True)
-               self._tx_start = CSR()
-
-               self.submodules.ev = EventManager()
-               self.ev.rx0 = EventSourcePulse()
-               self.ev.rx1 = EventSourcePulse()
-               self.ev.tx = EventSourcePulse()
-               self.ev.finalize()
-
-               self.membus = wishbone.Interface()
-
-               ###
-
-               init = Signal(reset=1)
-               self.sync += init.eq(0)
-               rx_ready_0 = Signal()
-               rx_ready_1 = Signal()
-               rx_pending_0 = self.ev.rx0.pending
-               rx_pending_1 = self.ev.rx1.pending
-               rx_pending_0_r = Signal()
-               rx_pending_1_r = Signal()
-               self.comb += [
-                       pads.rst_n.eq(~self._phy_reset.storage),
-
-                       rx_ready_0.eq(init | (rx_pending_0_r & ~rx_pending_0)),
-                       rx_ready_1.eq(init | (rx_pending_1_r & ~rx_pending_1)),
-
-                       self._tx_count.dat_w.eq(0),
-                       self._tx_count.we.eq(self.ev.tx.trigger)
-               ]
-               self.sync += [
-                       rx_pending_0_r.eq(rx_pending_0),
-                       rx_pending_1_r.eq(rx_pending_1)
-               ]
-               self.specials += Instance("minimac3",
-                               Instance.Input("sys_clk", ClockSignal()),
-                               Instance.Input("sys_rst", ResetSignal()),
-
-                               Instance.Output("rx_done_0", self.ev.rx0.trigger),
-                               Instance.Output("rx_count_0", self._rx_count_0.status),
-                               Instance.Output("rx_done_1", self.ev.rx1.trigger),
-                               Instance.Output("rx_count_1", self._rx_count_1.status),
-                               Instance.Input("rx_ready_0", rx_ready_0),
-                               Instance.Input("rx_ready_1", rx_ready_1),
-
-                               Instance.Input("tx_start", self._tx_start.re),
-                               Instance.Input("tx_count", self._tx_count.storage),
-                               Instance.Output("tx_done", self.ev.tx.trigger),
-
-                               Instance.Input("wb_adr_i", self.membus.adr),
-                               Instance.Input("wb_dat_i", self.membus.dat_w),
-                               Instance.Input("wb_sel_i", self.membus.sel),
-                               Instance.Input("wb_stb_i", self.membus.stb),
-                               Instance.Input("wb_cyc_i", self.membus.cyc),
-                               Instance.Input("wb_we_i", self.membus.we),
-                               Instance.Output("wb_dat_o", self.membus.dat_r),
-                               Instance.Output("wb_ack_o", self.membus.ack),
-
-                               Instance.Input("phy_tx_clk", ClockSignal("eth_tx")),
-                               Instance.Output("phy_tx_data", pads.tx_data),
-                               Instance.Output("phy_tx_en", pads.tx_en),
-                               Instance.Output("phy_tx_er", pads.tx_er),
-                               Instance.Input("phy_rx_clk", ClockSignal("eth_rx")),
-                               Instance.Input("phy_rx_data", pads.rx_data),
-                               Instance.Input("phy_dv", pads.dv),
-                               Instance.Input("phy_rx_er", pads.rx_er),
-                               Instance.Input("phy_col", pads.col),
-                               Instance.Input("phy_crs", pads.crs))
index a4c838873bc225026ddb349d303f35365ff441fe..986e255b3d17b55b0270770e1e5a0b34952e150a 100644 (file)
@@ -8,8 +8,6 @@ class MXCRG(Module):
                self.clock_domains.cd_sdram_half = ClockDomain()
                self.clock_domains.cd_sdram_full_wr = ClockDomain()
                self.clock_domains.cd_sdram_full_rd = ClockDomain()
-               self.clock_domains.cd_eth_rx = ClockDomain()
-               self.clock_domains.cd_eth_tx = ClockDomain()
                self.clock_domains.cd_base50 = ClockDomain(reset_less=True)
 
                self.clk4x_wr_strb = Signal()
@@ -28,21 +26,15 @@ class MXCRG(Module):
                        Instance.Input("clk50_pad", pads.clk50),
                        Instance.Input("trigger_reset", pads.trigger_reset),
 
-                       Instance.Input("eth_rx_clk_pad", pads.eth_rx_clk),
-                       Instance.Input("eth_tx_clk_pad", pads.eth_tx_clk),
-
                        Instance.Output("sys_clk", self.cd_sys.clk),
                        Instance.Output("sys_rst", self.cd_sys.rst),
                        Instance.Output("clk2x_270", self.cd_sdram_half.clk),
                        Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk),
                        Instance.Output("clk4x_rd", self.cd_sdram_full_rd.clk),
-                       Instance.Output("eth_rx_clk", self.cd_eth_rx.clk),
-                       Instance.Output("eth_tx_clk", self.cd_eth_tx.clk),
                        Instance.Output("base50_clk", self.cd_base50.clk),
 
                        Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb),
                        Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb),
                        Instance.Output("norflash_rst_n", pads.norflash_rst_n),
                        Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p),
-                       Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n),
-                       Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk))
+                       Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n))
index 80cefdb7ab623e33c984880cafb2cafb407c46d4..1c5c14a816e1f68de90fbb2daf1efbcb28415ad9 100644 (file)
@@ -176,7 +176,7 @@ void serialboot(void)
        }
 }
 
-#ifdef MINIMAC_BASE
+#ifdef ETHMAC_BASE
 
 #define LOCALIP1 192
 #define LOCALIP2 168
@@ -258,7 +258,7 @@ void flashboot(void)
                printf("Error: Invalid flash boot image length 0x%08x\n", length);
                return;
        }
-       
+
        printf("Loading %d bytes from flash...\n", length);
        memcpy((void *)SDRAM_BASE, flashbase, length);
        got_crc = crc32((unsigned char *)SDRAM_BASE, length);
index 29b141ce7aeba4e3a555ad0ffeeee0856a6e4981..32f77a43f2eacfc547bd0b1b41e092763b85374e 100644 (file)
@@ -319,7 +319,7 @@ static void help(void)
        puts("rcsr       - read processor CSR");
        puts("wcsr       - write processor CSR");
 #endif
-#ifdef MINIMAC_BASE
+#ifdef ETHMAC_BASE
        puts("netboot    - boot via TFTP");
 #endif
        puts("serialboot - boot via SFL");
@@ -361,10 +361,10 @@ static void do_command(char *c)
        else if(strcmp(token, "flashboot") == 0) flashboot();
 #endif
        else if(strcmp(token, "serialboot") == 0) serialboot();
-#ifdef MINIMAC_BASE
+#ifdef ETHMAC_BASE
        else if(strcmp(token, "netboot") == 0) netboot();
 #endif
-       
+
        else if(strcmp(token, "revision") == 0) printf("%08x\n", MSC_GIT_ID);
 
        else if(strcmp(token, "help") == 0) help();
@@ -373,7 +373,7 @@ static void do_command(char *c)
        else if(strcmp(token, "rcsr") == 0) rcsr(get_token(&c));
        else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c));
 #endif
-       
+
 #ifdef DFII_BASE
        else if(strcmp(token, "sdrrow") == 0) sdrrow(get_token(&c));
        else if(strcmp(token, "sdrsw") == 0) sdrsw();
@@ -390,7 +390,7 @@ static void do_command(char *c)
        else if(strcmp(token, "memtest") == 0) memtest();
        else if(strcmp(token, "sdrinit") == 0) sdrinit();
 #endif
-       
+
        else if(strcmp(token, "dfs") == 0) dfs(get_token(&c));
 
        else if(strcmp(token, "") != 0)
@@ -464,7 +464,7 @@ static int test_user_abort(void)
        printf("Automatic boot in 2 seconds...\n");
        printf("Q/ESC: abort boot\n");
        printf("F7:    boot from serial\n");
-#ifdef MINIMAC_BASE
+#ifdef ETHMAC_BASE
        printf("F8:    boot from network\n");
 #endif
        timer0_en_write(0);
@@ -483,7 +483,7 @@ static int test_user_abort(void)
                                serialboot();
                                return 0;
                        }
-#ifdef MINIMAC_BASE
+#ifdef ETHMAC_BASE
                        if(c == 0x07) {
                                netboot();
                                return 0;
@@ -502,7 +502,7 @@ static void boot_sequence(void)
                flashboot();
 #endif
                serialboot();
-#ifdef MINIMAC_BASE
+#ifdef ETHMAC_BASE
                netboot();
 #endif
                printf("No boot medium found\n");
@@ -522,7 +522,7 @@ int main(int i, char **c)
        printf("Revision %08x built "__DATE__" "__TIME__"\n\n", MSC_GIT_ID);
        crcbios();
        id_print();
-#ifdef MINIMAC_BASE
+#ifdef ETHMAC_BASE
        ethreset();
 #endif
 #ifdef DFII_BASE
@@ -534,7 +534,7 @@ int main(int i, char **c)
                boot_sequence();
        else
                printf("Memory initialization failed\n");
-       
+
        while(1) {
                putsnonl("\e[1mBIOS>\e[0m ");
                readstr(buffer, 64);
diff --git a/software/include/hw/ethmac_mem.h b/software/include/hw/ethmac_mem.h
new file mode 100644 (file)
index 0000000..c57e175
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __HW_ETHMAC_MEM_H
+#define __HW_ETHMAC_MEM_H
+
+#include <generated/mem.h>
+
+#define ETHMAC_RX0_BASE        ETHMAC_MEM_BASE
+#define ETHMAC_RX1_BASE        (ETHMAC_MEM_BASE+0x0800)
+#define ETHMAC_TX0_BASE        (ETHMAC_MEM_BASE+0x1000)
+#define ETHMAC_TX1_BASE        (ETHMAC_MEM_BASE+0x1800)
+
+#endif
index 01682e4c156e88ef99b791a17ea93f419c3a0a6a..911a1b68d2bd5f658537bf8bc019071f239f39ce 100644 (file)
@@ -16,9 +16,8 @@
 #define DFII_COMMAND_WRDATA    0x10
 #define DFII_COMMAND_RDDATA    0x20
 
-#define MINIMAC_EV_RX0 0x1
-#define MINIMAC_EV_RX1 0x2
-#define MINIMAC_EV_TX  0x4
+#define ETHMAC_EV_SRAM_WRITER  0x1
+#define ETHMAC_EV_SRAM_READER  0x1
 
 #define CLKGEN_STATUS_BUSY             0x1
 #define CLKGEN_STATUS_PROGDONE 0x2
diff --git a/software/include/hw/minimac_mem.h b/software/include/hw/minimac_mem.h
deleted file mode 100644 (file)
index b93cc68..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __HW_MINIMAC_MEM_H
-#define __HW_MINIMAC_MEM_H
-
-#include <generated/mem.h>
-
-#define MINIMAC_RX0_BASE       MINIMAC_MEM_BASE
-#define MINIMAC_RX1_BASE       (MINIMAC_MEM_BASE+0x0800)
-#define MINIMAC_TX_BASE                (MINIMAC_MEM_BASE+0x1000)
-
-#endif
index bd5e2a08b395d1316c15d3753fe3fa270e47ceca..a8faa45db228fa5ce6b04a23bf47f72fe0392088 100644 (file)
@@ -1,19 +1,25 @@
 #include <generated/csr.h>
-#ifdef MINIMAC_BASE
+#ifdef ETHMAC_BASE
 
 #include <stdio.h>
 #include <system.h>
 #include <crc.h>
 #include <hw/flags.h>
-#include <hw/minimac_mem.h>
+#include <hw/ethmac_mem.h>
 
 #include <net/microudp.h>
 
 #define ETHERTYPE_ARP 0x0806
 #define ETHERTYPE_IP  0x0800
 
+#ifdef CSR_ETHMAC_HW_PREAMBLE_CRC_ADDR
+#define HW_PREAMBLE_CRC
+#endif
+
 struct ethernet_header {
+#ifndef HW_PREAMBLE_CRC
        unsigned char preamble[8];
+#endif
        unsigned char destmac[6];
        unsigned char srcmac[6];
        unsigned short ethertype;
@@ -23,9 +29,11 @@ static void fill_eth_header(struct ethernet_header *h, const unsigned char *dest
 {
        int i;
 
+#ifndef HW_PREAMBLE_CRC
        for(i=0;i<7;i++)
                h->preamble[i] = 0x55;
        h->preamble[7] = 0xd5;
+#endif
        for(i=0;i<6;i++)
                h->destmac[i] = destmac[i];
        for(i=0;i<6;i++)
@@ -35,6 +43,11 @@ static void fill_eth_header(struct ethernet_header *h, const unsigned char *dest
 
 #define ARP_HWTYPE_ETHERNET 0x0001
 #define ARP_PROTO_IP        0x0800
+#ifndef HW_PREAMBLE_CRC
+#define ARP_PACKET_LENGTH 68
+#else
+#define ARP_PACKET_LENGTH 60
+#endif
 
 #define ARP_OPCODE_REQUEST  0x0001
 #define ARP_OPCODE_REPLY    0x0002
@@ -97,27 +110,37 @@ typedef union {
 } ethernet_buffer;
 
 
+static unsigned int rxslot;
 static unsigned int rxlen;
 static ethernet_buffer *rxbuffer;
 static ethernet_buffer *rxbuffer0;
 static ethernet_buffer *rxbuffer1;
+static unsigned int txslot;
 static unsigned int txlen;
 static ethernet_buffer *txbuffer;
+static ethernet_buffer *txbuffer0;
+static ethernet_buffer *txbuffer1;
 
 static void send_packet(void)
 {
+#ifndef HW_PREAMBLE_CRC
        unsigned int crc;
-       
        crc = crc32(&txbuffer->raw[8], txlen-8);
        txbuffer->raw[txlen  ] = (crc & 0xff);
        txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8;
        txbuffer->raw[txlen+2] = (crc & 0xff0000) >> 16;
        txbuffer->raw[txlen+3] = (crc & 0xff000000) >> 24;
        txlen += 4;
-       minimac_tx_count_write(txlen);
-       minimac_tx_start_write(1);
-       while(!(minimac_ev_pending_read() & MINIMAC_EV_TX));
-       minimac_ev_pending_write(MINIMAC_EV_TX);
+#endif
+       ethmac_sram_reader_slot_write(txslot);
+       ethmac_sram_reader_length_write(txlen);
+       while(!(ethmac_sram_reader_ready_read()));
+       ethmac_sram_reader_start_write(1);
+       txslot = (txslot+1)%2;
+       if (txslot)
+               txbuffer = txbuffer1;
+       else
+               txbuffer = txbuffer0;
 }
 
 static unsigned char my_mac[6];
@@ -132,7 +155,7 @@ static void process_arp(void)
        const struct arp_frame *rx_arp = &rxbuffer->frame.contents.arp;
        struct arp_frame *tx_arp = &txbuffer->frame.contents.arp;
 
-       if(rxlen < 68) return;
+       if(rxlen < ARP_PACKET_LENGTH) return;
        if(rx_arp->hwtype != ARP_HWTYPE_ETHERNET) return;
        if(rx_arp->proto != ARP_PROTO_IP) return;
        if(rx_arp->hwsize != 6) return;
@@ -148,12 +171,12 @@ static void process_arp(void)
        if(rx_arp->opcode == ARP_OPCODE_REQUEST) {
                if(rx_arp->target_ip == my_ip) {
                        int i;
-                       
+
                        fill_eth_header(&txbuffer->frame.eth_header,
                                rx_arp->sender_mac,
                                my_mac,
                                ETHERTYPE_ARP);
-                       txlen = 68;
+                       txlen = ARP_PACKET_LENGTH;
                        tx_arp->hwtype = ARP_HWTYPE_ETHERNET;
                        tx_arp->proto = ARP_PROTO_IP;
                        tx_arp->hwsize = 6;
@@ -194,7 +217,7 @@ int microudp_arp_resolve(unsigned int ip)
                                broadcast,
                                my_mac,
                                ETHERTYPE_ARP);
-               txlen = 68;
+               txlen = ARP_PACKET_LENGTH;
                arp->hwtype = ARP_HWTYPE_ETHERNET;
                arp->proto = ARP_PROTO_IP;
                arp->hwsize = 6;
@@ -259,19 +282,19 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int
 {
        struct pseudo_header h;
        unsigned int r;
-       
+
        if((cached_mac[0] == 0) && (cached_mac[1] == 0) && (cached_mac[2] == 0)
                && (cached_mac[3] == 0) && (cached_mac[4] == 0) && (cached_mac[5] == 0))
                return 0;
 
        txlen = length + sizeof(struct ethernet_header) + sizeof(struct udp_frame);
-       if(txlen < 68) txlen = 68;
-       
+       if(txlen < ARP_PACKET_LENGTH) txlen = ARP_PACKET_LENGTH;
+
        fill_eth_header(&txbuffer->frame.eth_header,
                cached_mac,
                my_mac,
                ETHERTYPE_IP);
-       
+
        txbuffer->frame.contents.udp.ip.version = IP_IPV4;
        txbuffer->frame.contents.udp.ip.diff_services = 0;
        txbuffer->frame.contents.udp.ip.total_length = length + sizeof(struct udp_frame);
@@ -299,7 +322,7 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int
        r = ip_checksum(r, &txbuffer->frame.contents.udp.udp,
                sizeof(struct udp_header)+length, 1);
        txbuffer->frame.contents.udp.udp.checksum = r;
-       
+
        send_packet();
 
        return 1;
@@ -332,14 +355,18 @@ void microudp_set_callback(udp_callback callback)
 
 static void process_frame(void)
 {
-       int i;
-       unsigned int received_crc;
-       unsigned int computed_crc;
-
        flush_cpu_dcache();
+
+#ifndef HW_PREAMBLE_CRC
+       int i;
        for(i=0;i<7;i++)
                if(rxbuffer->frame.eth_header.preamble[i] != 0x55) return;
        if(rxbuffer->frame.eth_header.preamble[7] != 0xd5) return;
+#endif
+
+#ifndef HW_PREAMBLE_CRC
+       unsigned int received_crc;
+       unsigned int computed_crc;
        received_crc = ((unsigned int)rxbuffer->raw[rxlen-1] << 24)
                |((unsigned int)rxbuffer->raw[rxlen-2] << 16)
                |((unsigned int)rxbuffer->raw[rxlen-3] <<  8)
@@ -348,6 +375,8 @@ static void process_frame(void)
        if(received_crc != computed_crc) return;
 
        rxlen -= 4; /* strip CRC here to be consistent with TX */
+#endif
+
        if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_ARP) process_arp();
        else if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_IP) process_ip();
 }
@@ -355,12 +384,19 @@ static void process_frame(void)
 void microudp_start(const unsigned char *macaddr, unsigned int ip)
 {
        int i;
+       ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER);
+       ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER);
+
+       rxbuffer0 = (ethernet_buffer *)ETHMAC_RX0_BASE;
+       rxbuffer1 = (ethernet_buffer *)ETHMAC_RX1_BASE;
+       txbuffer0 = (ethernet_buffer *)ETHMAC_TX0_BASE;
+       txbuffer1 = (ethernet_buffer *)ETHMAC_TX1_BASE;
 
-       minimac_ev_pending_write(MINIMAC_EV_RX0 | MINIMAC_EV_RX1 | MINIMAC_EV_TX);
-       
-       rxbuffer0 = (ethernet_buffer *)MINIMAC_RX0_BASE;
-       rxbuffer1 = (ethernet_buffer *)MINIMAC_RX1_BASE;
-       txbuffer = (ethernet_buffer *)MINIMAC_TX_BASE;
+       rxslot = 0;
+       txslot = 0;
+
+       rxbuffer = rxbuffer0;
+       txbuffer = txbuffer0;
 
        for(i=0;i<6;i++)
                my_mac[i] = macaddr[i];
@@ -375,17 +411,15 @@ void microudp_start(const unsigned char *macaddr, unsigned int ip)
 
 void microudp_service(void)
 {
-       if(minimac_ev_pending_read() & MINIMAC_EV_RX0) {
-               rxlen = minimac_rx_count_0_read();
-               rxbuffer = rxbuffer0;
-               process_frame();
-               minimac_ev_pending_write(MINIMAC_EV_RX0);
-       }
-       if(minimac_ev_pending_read() & MINIMAC_EV_RX1) {
-               rxlen = minimac_rx_count_1_read();
-               rxbuffer = rxbuffer1;
+       if(ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER) {
+               rxslot = ethmac_sram_writer_slot_read();
+               rxlen = ethmac_sram_writer_length_read();
+               if (rxslot)
+                       rxbuffer = rxbuffer1;
+               else
+                       rxbuffer = rxbuffer0;
                process_frame();
-               minimac_ev_pending_write(MINIMAC_EV_RX1);
+               ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER);
        }
 }
 
@@ -401,12 +435,12 @@ static void busy_wait(unsigned int ds)
 
 void ethreset(void)
 {
-       minimac_phy_reset_write(0);
+       ethphy_crg_reset_write(0);
        busy_wait(2);
        /* that pesky ethernet PHY needs two resets at times... */
-       minimac_phy_reset_write(1);
+       ethphy_crg_reset_write(1);
        busy_wait(2);
-       minimac_phy_reset_write(0);
+       ethphy_crg_reset_write(0);
        busy_wait(2);
 }
 
index 2bf0eac6a416f4e7a9f52c304901462e6dd7d805..457968442829ac991c20fab25cc4e53c383810c3 100644 (file)
@@ -70,7 +70,7 @@ static void rx_callback(uint32_t src_ip, uint16_t src_port,
        uint16_t block;
        int i;
        int offset;
-       
+
        if(length < 4) return;
        if(dst_port != PORT_IN) return;
        opcode = data[0] << 8 | data[1];
@@ -89,7 +89,8 @@ static void rx_callback(uint32_t src_ip, uint16_t src_port,
                total_length += length;
                if(length < BLOCK_SIZE)
                        transfer_finished = 1;
-               
+
+               packet_data = microudp_get_tx_buffer();
                length = format_ack(packet_data, block);
                microudp_send(PORT_IN, src_port, length);
        }
@@ -105,19 +106,19 @@ int tftp_get(uint32_t ip, const char *filename, void *buffer)
        int tries;
        int i;
        int length_before;
-       
+
        if(!microudp_arp_resolve(ip))
                return -1;
 
        microudp_set_callback(rx_callback);
 
-       packet_data = microudp_get_tx_buffer();
        dst_buffer = buffer;
 
        total_length = 0;
        transfer_finished = 0;
        tries = 5;
        while(1) {
+               packet_data = microudp_get_tx_buffer();
                len = format_request(packet_data, TFTP_RRQ, filename);
                microudp_send(PORT_IN, PORT_OUT, len);
                for(i=0;i<2000000;i++) {
@@ -156,7 +157,7 @@ int tftp_put(uint32_t ip, const char *filename, const void *buffer, int size)
        int tries;
        int i;
        int block = 0, sent = 0;
-       
+
        if(!microudp_arp_resolve(ip))
                return -1;
 
@@ -168,6 +169,7 @@ int tftp_put(uint32_t ip, const char *filename, const void *buffer, int size)
        transfer_finished = 0;
        tries = 5;
        while(1) {
+               packet_data = microudp_get_tx_buffer();
                len = format_request(packet_data, TFTP_WRQ, filename);
                microudp_send(PORT_IN, PORT_OUT, len);
                for(i=0;i<2000000;i++) {
@@ -189,6 +191,7 @@ send_data:
                send = sent+BLOCK_SIZE > size ? size-sent : BLOCK_SIZE;
                tries = 5;
                while(1) {
+                       packet_data = microudp_get_tx_buffer();
                        len = format_data(packet_data, block, buffer, send);
                        microudp_send(PORT_IN, data_port, len);
                        for(i=0;i<12000000;i++) {
index 8c78ad7637a396e6e838941f4a35a6db70ed6a94..1aab9ef47beb42fcfdc76edc867650cfacb32c47 100644 (file)
@@ -1,9 +1,10 @@
 from migen.fhdl.std import *
 from migen.genlib.resetsync import AsyncResetSynchronizer
 
-from misoclib import lasmicon, spiflash
+from misoclib import lasmicon, spiflash, ethmac
 from misoclib.sdramphy import k7ddrphy
 from misoclib.gensoc import SDRAMSoC
+from misoclib.ethmac.phys import gmii
 
 class _CRG(Module):
        def __init__(self, platform):
@@ -104,4 +105,24 @@ class BaseSoC(SDRAMSoC):
                self.flash_boot_address = 0xb00000
                self.register_rom(self.spiflash.bus)
 
+class MiniSoC(BaseSoC):
+       csr_map = {
+               "ethphy":               10,
+               "ethmac":               11,
+       }
+       csr_map.update(BaseSoC.csr_map)
+
+       interrupt_map = {
+               "ethmac":               2,
+       }
+       interrupt_map.update(BaseSoC.interrupt_map)
+
+       def __init__(self, platform, **kwargs):
+               BaseSoC.__init__(self, platform, **kwargs)
+
+               self.submodules.ethphy = gmii.GMIIPHY(platform.request("eth_clocks"), platform.request("eth"))
+               self.submodules.ethmac = ethmac.EthMAC(phy=self.ethphy, with_hw_preamble_crc=True)
+               self.add_wb_slave(lambda a: a[26:29] == 3, self.ethmac.bus)
+               self.add_cpu_memory_region("ethmac_mem", 0xb0000000, 0x2000)
+
 default_subtarget = BaseSoC
index 79ad4ae3e8fed5c25f6e0c20cfe0d6bc2cca0bd3..d23380158ee26bca26a803a47c5f37af1837b605 100644 (file)
@@ -4,9 +4,10 @@ from fractions import Fraction
 from migen.fhdl.std import *
 from mibuild.generic_platform import ConstraintError
 
-from misoclib import lasmicon, mxcrg, norflash16, minimac3, framebuffer, gpio
+from misoclib import lasmicon, mxcrg, norflash16, ethmac, framebuffer, gpio
 from misoclib.sdramphy import s6ddrphy
 from misoclib.gensoc import SDRAMSoC
+from misoclib.ethmac.phys import mii
 
 class _MXClockPads:
        def __init__(self, platform):
@@ -20,10 +21,6 @@ class _MXClockPads:
                ddram_clock = platform.request("ddram_clock")
                self.ddr_clk_p = ddram_clock.p
                self.ddr_clk_n = ddram_clock.n
-               eth_clocks = platform.request("eth_clocks")
-               self.eth_phy_clk = eth_clocks.phy
-               self.eth_rx_clk = eth_clocks.rx
-               self.eth_tx_clk = eth_clocks.tx
 
 class BaseSoC(SDRAMSoC):
        default_platform = "mixxeo" # also supports m1
@@ -75,12 +72,13 @@ PIN "mxcrg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE;
 
 class MiniSoC(BaseSoC):
        csr_map = {
-               "minimac":              10,
+               "ethphy":               10,
+               "ethmac":               11,
        }
        csr_map.update(BaseSoC.csr_map)
 
        interrupt_map = {
-               "minimac":              2,
+               "ethmac":               2,
        }
        interrupt_map.update(BaseSoC.interrupt_map)
 
@@ -93,10 +91,10 @@ class MiniSoC(BaseSoC):
                        self.submodules.buttons = gpio.GPIOIn(Cat(platform.request("user_btn", 0), platform.request("user_btn", 2)))
                        self.submodules.leds = gpio.GPIOOut(Cat(platform.request("user_led", i) for i in range(2)))
 
-               self.submodules.minimac = minimac3.MiniMAC(platform.request("eth"))
-               self.add_wb_slave(lambda a: a[26:29] == 3, self.minimac.membus)
-               self.add_cpu_memory_region("minimac_mem", 0xb0000000, 0x1800)
-               platform.add_source_dir(os.path.join("verilog", "minimac3"))
+               self.submodules.ethphy = mii.MIIPHY(platform.request("eth_clocks"), platform.request("eth"))
+               self.submodules.ethmac = ethmac.EthMAC(phy=self.ethphy, with_hw_preamble_crc=False)
+               self.add_wb_slave(lambda a: a[26:29] == 3, self.ethmac.bus)
+               self.add_cpu_memory_region("ethmac_mem", 0xb0000000, 0x2000)
 
 def get_vga_dvi(platform):
        try:
diff --git a/verilog/minimac3/minimac3.v b/verilog/minimac3/minimac3.v
deleted file mode 100644 (file)
index a1e6bd8..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-module minimac3(
-       input sys_clk,
-       input sys_rst,
-
-       /* Control */
-       input rx_ready_0,
-       output rx_done_0,
-       output [10:0] rx_count_0,
-       input rx_ready_1,
-       output rx_done_1,
-       output [10:0] rx_count_1,
-       
-       input tx_start,
-       output tx_done,
-       input [10:0] tx_count,
-
-       /* WISHBONE to access RAM */
-       input [29:0] wb_adr_i,
-       output [31:0] wb_dat_o,
-       input [31:0] wb_dat_i,
-       input [3:0] wb_sel_i,
-       input wb_stb_i,
-       input wb_cyc_i,
-       output wb_ack_o,
-       input wb_we_i,
-
-       /* To PHY */
-       input phy_tx_clk,
-       output [3:0] phy_tx_data,
-       output phy_tx_en,
-       output phy_tx_er,
-       input phy_rx_clk,
-       input [3:0] phy_rx_data,
-       input phy_dv,
-       input phy_rx_er,
-       input phy_col,
-       input phy_crs
-);
-
-wire [1:0] phy_rx_ready;
-wire [1:0] phy_rx_done;
-wire [10:0] phy_rx_count_0;
-wire [10:0] phy_rx_count_1;
-wire phy_tx_start;
-wire phy_tx_done;
-wire [10:0] phy_tx_count;
-
-minimac3_sync sync(
-       .sys_clk(sys_clk),
-       .phy_rx_clk(phy_rx_clk),
-       .phy_tx_clk(phy_tx_clk),
-       
-       .sys_rx_ready({rx_ready_1, rx_ready_0}),
-       .sys_rx_done({rx_done_1, rx_done_0}),
-       .sys_rx_count_0(rx_count_0),
-       .sys_rx_count_1(rx_count_1),
-       .sys_tx_start(tx_start),
-       .sys_tx_done(tx_done),
-       .sys_tx_count(tx_count),
-       
-       .phy_rx_ready(phy_rx_ready),
-       .phy_rx_done(phy_rx_done),
-       .phy_rx_count_0(phy_rx_count_0),
-       .phy_rx_count_1(phy_rx_count_1),
-       .phy_tx_start(phy_tx_start),
-       .phy_tx_done(phy_tx_done),
-       .phy_tx_count(phy_tx_count)
-);
-
-wire [7:0] rxb0_dat;
-wire [10:0] rxb0_adr;
-wire rxb0_we;
-wire [7:0] rxb1_dat;
-wire [10:0] rxb1_adr;
-wire rxb1_we;
-wire [7:0] txb_dat;
-wire [10:0] txb_adr;
-minimac3_memory memory(
-       .sys_clk(sys_clk),
-       .sys_rst(sys_rst),
-       .phy_rx_clk(phy_rx_clk),
-       .phy_tx_clk(phy_tx_clk),
-
-       .wb_adr_i(wb_adr_i),
-       .wb_dat_o(wb_dat_o),
-       .wb_dat_i(wb_dat_i),
-       .wb_sel_i(wb_sel_i),
-       .wb_stb_i(wb_stb_i),
-       .wb_cyc_i(wb_cyc_i),
-       .wb_ack_o(wb_ack_o),
-       .wb_we_i(wb_we_i),
-       
-       .rxb0_dat(rxb0_dat),
-       .rxb0_adr(rxb0_adr),
-       .rxb0_we(rxb0_we),
-       .rxb1_dat(rxb1_dat),
-       .rxb1_adr(rxb1_adr),
-       .rxb1_we(rxb1_we),
-       
-       .txb_dat(txb_dat),
-       .txb_adr(txb_adr)
-);
-
-minimac3_tx tx(
-       .phy_tx_clk(phy_tx_clk),
-       
-       .tx_start(phy_tx_start),
-       .tx_done(phy_tx_done),
-       .tx_count(phy_tx_count),
-       .txb_dat(txb_dat),
-       .txb_adr(txb_adr),
-       
-       .phy_tx_en(phy_tx_en),
-       .phy_tx_data(phy_tx_data)
-);
-assign phy_tx_er = 1'b0;
-
-minimac3_rx rx(
-       .phy_rx_clk(phy_rx_clk),
-       
-       .rx_ready(phy_rx_ready),
-       .rx_done(phy_rx_done),
-       .rx_count_0(phy_rx_count_0),
-       .rx_count_1(phy_rx_count_1),
-       
-       .rxb0_dat(rxb0_dat),
-       .rxb0_adr(rxb0_adr),
-       .rxb0_we(rxb0_we),
-       .rxb1_dat(rxb1_dat),
-       .rxb1_adr(rxb1_adr),
-       .rxb1_we(rxb1_we),
-       
-       .phy_dv(phy_dv),
-       .phy_rx_data(phy_rx_data),
-       .phy_rx_er(phy_rx_er)
-);
-
-endmodule
diff --git a/verilog/minimac3/minimac3_memory.v b/verilog/minimac3/minimac3_memory.v
deleted file mode 100644 (file)
index f527bb3..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* TODO: use behavioral BRAM models (Xst can extract byte WE) */
-
-module minimac3_memory(
-       input sys_clk,
-       input sys_rst,
-       input phy_rx_clk,
-       input phy_tx_clk,
-       
-       input [29:0] wb_adr_i,
-       output [31:0] wb_dat_o,
-       input [31:0] wb_dat_i,
-       input [3:0] wb_sel_i,
-       input wb_stb_i,
-       input wb_cyc_i,
-       output reg wb_ack_o,
-       input wb_we_i,
-       
-       input [7:0] rxb0_dat,
-       input [10:0] rxb0_adr,
-       input rxb0_we,
-       input [7:0] rxb1_dat,
-       input [10:0] rxb1_adr,
-       input rxb1_we,
-       
-       output [7:0] txb_dat,
-       input [10:0] txb_adr
-
-);
-
-wire wb_en = wb_cyc_i & wb_stb_i;
-wire [1:0] wb_buf = wb_adr_i[10:9];
-wire [31:0] wb_dat_i_le = {wb_dat_i[7:0], wb_dat_i[15:8], wb_dat_i[23:16], wb_dat_i[31:24]};
-wire [3:0] wb_sel_i_le = {wb_sel_i[0], wb_sel_i[1], wb_sel_i[2], wb_sel_i[3]};
-
-wire [31:0] rxb0_wbdat;
-RAMB16BWER #(
-       .DATA_WIDTH_A(36),
-       .DATA_WIDTH_B(9),
-       .DOA_REG(0),
-       .DOB_REG(0),
-       .EN_RSTRAM_A("FALSE"),
-       .EN_RSTRAM_B("FALSE"),
-       .SIM_DEVICE("SPARTAN6"),
-       .WRITE_MODE_A("WRITE_FIRST"),
-       .WRITE_MODE_B("WRITE_FIRST")
-) rxb0 (
-       .DIA(wb_dat_i_le),
-       .DIPA(4'd0),
-       .DOA(rxb0_wbdat),
-       .ADDRA({wb_adr_i[8:0], 5'd0}),
-       .WEA({4{wb_en & wb_we_i & (wb_buf == 2'b00)}} & wb_sel_i_le),
-       .ENA(1'b1),
-       .RSTA(1'b0),
-       .CLKA(sys_clk),
-
-       .DIB(rxb0_dat),
-       .DIPB(1'd0),
-       .DOB(),
-       .ADDRB({rxb0_adr, 3'd0}),
-       .WEB({4{rxb0_we}}),
-       .ENB(1'b1),
-       .RSTB(1'b0),
-       .CLKB(phy_rx_clk)
-);
-
-wire [31:0] rxb1_wbdat;
-RAMB16BWER #(
-       .DATA_WIDTH_A(36),
-       .DATA_WIDTH_B(9),
-       .DOA_REG(0),
-       .DOB_REG(0),
-       .EN_RSTRAM_A("FALSE"),
-       .EN_RSTRAM_B("FALSE"),
-       .SIM_DEVICE("SPARTAN6"),
-       .WRITE_MODE_A("WRITE_FIRST"),
-       .WRITE_MODE_B("WRITE_FIRST")
-) rxb1 (
-       .DIA(wb_dat_i_le),
-       .DIPA(4'd0),
-       .DOA(rxb1_wbdat),
-       .ADDRA({wb_adr_i[8:0], 5'd0}),
-       .WEA({4{wb_en & wb_we_i & (wb_buf == 2'b01)}} & wb_sel_i_le),
-       .ENA(1'b1),
-       .RSTA(1'b0),
-       .CLKA(sys_clk),
-
-       .DIB(rxb1_dat),
-       .DIPB(1'd0),
-       .DOB(),
-       .ADDRB({rxb1_adr, 3'd0}),
-       .WEB({4{rxb1_we}}),
-       .ENB(1'b1),
-       .RSTB(1'b0),
-       .CLKB(phy_rx_clk)
-);
-
-wire [31:0] txb_wbdat;
-RAMB16BWER #(
-       .DATA_WIDTH_A(36),
-       .DATA_WIDTH_B(9),
-       .DOA_REG(0),
-       .DOB_REG(0),
-       .EN_RSTRAM_A("FALSE"),
-       .EN_RSTRAM_B("FALSE"),
-       .SIM_DEVICE("SPARTAN6"),
-       .WRITE_MODE_A("WRITE_FIRST"),
-       .WRITE_MODE_B("WRITE_FIRST")
-) txb (
-       .DIA(wb_dat_i_le),
-       .DIPA(4'd0),
-       .DOA(txb_wbdat),
-       .ADDRA({wb_adr_i[8:0], 5'd0}),
-       .WEA({4{wb_en & wb_we_i & (wb_buf == 2'b10)}} & wb_sel_i_le),
-       .ENA(1'b1),
-       .RSTA(1'b0),
-       .CLKA(sys_clk),
-
-       .DIB(8'd0),
-       .DIPB(1'd0),
-       .DOB(txb_dat),
-       .ADDRB({txb_adr, 3'd0}),
-       .WEB(4'd0),
-       .ENB(1'b1),
-       .RSTB(1'b0),
-       .CLKB(phy_tx_clk)
-);
-
-always @(posedge sys_clk) begin
-       if(sys_rst)
-               wb_ack_o <= 1'b0;
-       else begin
-               wb_ack_o <= 1'b0;
-               if(wb_en & ~wb_ack_o)
-                       wb_ack_o <= 1'b1;
-       end
-end
-
-reg [1:0] wb_buf_r;
-always @(posedge sys_clk)
-       wb_buf_r <= wb_buf;
-
-reg [31:0] wb_dat_o_le;
-always @(*) begin
-       case(wb_buf_r)
-               2'b00: wb_dat_o_le = rxb0_wbdat;
-               2'b01: wb_dat_o_le = rxb1_wbdat;
-               default: wb_dat_o_le = txb_wbdat;
-       endcase
-end
-assign wb_dat_o = {wb_dat_o_le[7:0], wb_dat_o_le[15:8], wb_dat_o_le[23:16], wb_dat_o_le[31:24]};
-
-endmodule
diff --git a/verilog/minimac3/minimac3_rx.v b/verilog/minimac3/minimac3_rx.v
deleted file mode 100644 (file)
index 6007fa6..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-module minimac3_rx(
-       input phy_rx_clk,
-       
-       input [1:0] rx_ready,
-       output [1:0] rx_done,
-       output reg [10:0] rx_count_0,
-       output reg [10:0] rx_count_1,
-       
-       output [7:0] rxb0_dat,
-       output [10:0] rxb0_adr,
-       output rxb0_we,
-       output [7:0] rxb1_dat,
-       output [10:0] rxb1_adr,
-       output rxb1_we,
-       
-       input phy_dv,
-       input [3:0] phy_rx_data,
-       input phy_rx_er
-);
-
-reg [1:0] available_slots;
-always @(posedge phy_rx_clk)
-       available_slots <= (available_slots & ~rx_done) | rx_ready;
-initial available_slots <= 2'd0;
-
-reg [1:0] used_slot;
-reg used_slot_update;
-always @(posedge phy_rx_clk) begin
-       if(used_slot_update) begin
-               used_slot[0] <= available_slots[0];
-               used_slot[1] <= available_slots[1] & ~available_slots[0];
-       end
-end
-
-reg rx_done_ctl;
-assign rx_done = {2{rx_done_ctl}} & used_slot;
-
-reg rx_count_reset_ctl;
-reg rx_count_inc_ctl;
-wire [1:0] rx_count_reset = {2{rx_count_reset_ctl}} & used_slot;
-wire [1:0] rx_count_inc = {2{rx_count_inc_ctl}} & used_slot;
-always @(posedge phy_rx_clk) begin
-       if(rx_count_reset[0])
-               rx_count_0 <= 11'd0;
-       else if(rx_count_inc[0])
-               rx_count_0 <= rx_count_0 + 11'd1;
-       if(rx_count_reset[1])
-               rx_count_1 <= 11'd0;
-       else if(rx_count_inc[1])
-               rx_count_1 <= rx_count_1 + 11'd1;
-end
-
-assign rxb0_adr = rx_count_0;
-assign rxb1_adr = rx_count_1;
-reg rxb_we_ctl;
-assign rxb0_we = rxb_we_ctl & used_slot[0];
-assign rxb1_we = rxb_we_ctl & used_slot[1];
-
-reg [3:0] lo;
-reg [3:0] hi;
-reg [1:0] load_nibble;
-always @(posedge phy_rx_clk) begin
-       if(load_nibble[0])
-               lo <= phy_rx_data;
-       if(load_nibble[1])
-               hi <= phy_rx_data;
-end
-assign rxb0_dat = {hi, lo};
-assign rxb1_dat = {hi, lo};
-
-reg [1:0] state;
-reg [1:0] next_state;
-
-parameter IDLE         = 2'd0;
-parameter LOAD_LO      = 2'd1;
-parameter LOAD_HI      = 2'd2;
-parameter TERMINATE    = 2'd3;
-
-initial state <= IDLE;
-always @(posedge phy_rx_clk)
-       state <= next_state;
-
-always @(*) begin
-       used_slot_update = 1'b0;
-       rx_done_ctl = 1'b0;
-       rx_count_reset_ctl = 1'b0;
-       rx_count_inc_ctl = 1'b0;
-       rxb_we_ctl = 1'b0;
-       load_nibble = 2'b00;
-       
-       next_state = state;
-       case(state)
-               IDLE: begin
-                       used_slot_update = 1'b1;
-                       if(phy_dv) begin
-                               rx_count_reset_ctl = 1'b1;
-                               used_slot_update = 1'b0;
-                               load_nibble = 2'b01;
-                               next_state = LOAD_HI;
-                       end
-               end
-               LOAD_LO: begin
-                       rxb_we_ctl = 1'b1;
-                       rx_count_inc_ctl = 1'b1;
-                       if(phy_dv) begin
-                               load_nibble = 2'b01;
-                               next_state = LOAD_HI;
-                       end else begin
-                               rx_done_ctl = 1'b1;
-                               next_state = TERMINATE;
-                       end
-               end
-               LOAD_HI: begin
-                       if(phy_dv) begin
-                               load_nibble = 2'b10;
-                               next_state = LOAD_LO;
-                       end else begin
-                               rx_done_ctl = 1'b1;
-                               next_state = TERMINATE;
-                       end
-               end
-               TERMINATE: begin
-                       used_slot_update = 1'b1;
-                       next_state = IDLE;
-               end
-       endcase
-end
-
-endmodule
diff --git a/verilog/minimac3/minimac3_sync.v b/verilog/minimac3/minimac3_sync.v
deleted file mode 100644 (file)
index c169ce2..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-module minimac3_sync(
-       input sys_clk,
-       input phy_rx_clk,
-       input phy_tx_clk,
-       
-       input [1:0] sys_rx_ready,
-       output [1:0] sys_rx_done,
-       output reg [10:0] sys_rx_count_0,
-       output reg [10:0] sys_rx_count_1,
-       
-       input sys_tx_start,
-       output sys_tx_done,
-       input [10:0] sys_tx_count,
-       
-       output [1:0] phy_rx_ready,
-       input [1:0] phy_rx_done,
-       input [10:0] phy_rx_count_0,
-       input [10:0] phy_rx_count_1,
-       
-       output phy_tx_start,
-       input phy_tx_done,
-       output reg [10:0] phy_tx_count
-);
-
-psync rx_ready_0(
-       .clk1(sys_clk),
-       .i(sys_rx_ready[0]),
-       .clk2(phy_rx_clk),
-       .o(phy_rx_ready[0])
-);
-psync rx_ready_1(
-       .clk1(sys_clk),
-       .i(sys_rx_ready[1]),
-       .clk2(phy_rx_clk),
-       .o(phy_rx_ready[1])
-);
-psync rx_done_0(
-       .clk1(phy_rx_clk),
-       .i(phy_rx_done[0]),
-       .clk2(sys_clk),
-       .o(sys_rx_done[0])
-);
-psync rx_done_1(
-       .clk1(phy_rx_clk),
-       .i(phy_rx_done[1]),
-       .clk2(sys_clk),
-       .o(sys_rx_done[1])
-);
-reg [10:0] sys_rx_count_0_r;
-reg [10:0] sys_rx_count_1_r;
-always @(posedge sys_clk) begin
-       sys_rx_count_0_r <= phy_rx_count_0;
-       sys_rx_count_0 <= sys_rx_count_0_r;
-       sys_rx_count_1_r <= phy_rx_count_1;
-       sys_rx_count_1 <= sys_rx_count_1_r;
-end
-
-psync tx_start(
-       .clk1(sys_clk),
-       .i(sys_tx_start),
-       .clk2(phy_tx_clk),
-       .o(phy_tx_start)
-);
-psync tx_done(
-       .clk1(phy_tx_clk),
-       .i(phy_tx_done),
-       .clk2(sys_clk),
-       .o(sys_tx_done)
-);
-reg [10:0] phy_tx_count_r;
-always @(posedge phy_tx_clk) begin
-       phy_tx_count_r <= sys_tx_count;
-       phy_tx_count <= phy_tx_count_r;
-end
-
-endmodule
diff --git a/verilog/minimac3/minimac3_tx.v b/verilog/minimac3/minimac3_tx.v
deleted file mode 100644 (file)
index caf901a..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-module minimac3_tx(
-       input phy_tx_clk,
-
-       input tx_start,
-       output reg tx_done,
-       input [10:0] tx_count,
-       input [7:0] txb_dat,
-       output [10:0] txb_adr,
-       
-       output reg phy_tx_en,
-       output reg [3:0] phy_tx_data
-);
-
-reg phy_tx_en_r;
-reg phy_tx_data_sel;
-wire [3:0] phy_tx_data_r = phy_tx_data_sel ? txb_dat[7:4] : txb_dat[3:0];
-always @(posedge phy_tx_clk) begin
-       phy_tx_en <= phy_tx_en_r;
-       phy_tx_data <= phy_tx_data_r;
-end
-
-reg [10:0] byte_count;
-reg byte_count_reset;
-reg byte_count_inc;
-always @(posedge phy_tx_clk) begin
-       if(byte_count_reset)
-               byte_count <= 11'd0;
-       else if(byte_count_inc)
-               byte_count <= byte_count + 11'd1;
-end
-assign txb_adr = byte_count;
-wire byte_count_max = byte_count == tx_count;
-
-parameter IDLE         = 2'd0;
-parameter SEND_LO      = 2'd1;
-parameter SEND_HI      = 2'd2;
-parameter TERMINATE    = 2'd3;
-
-reg [1:0] state;
-reg [1:0] next_state;
-
-initial state <= IDLE;
-always @(posedge phy_tx_clk)
-       state <= next_state;
-
-always @(*) begin
-       phy_tx_en_r = 1'b0;
-       phy_tx_data_sel = 1'b0;
-       byte_count_reset = 1'b0;
-       byte_count_inc = 1'b0;
-       tx_done = 1'b0;
-       
-       next_state = state;
-       
-       case(state)
-               IDLE: begin
-                       byte_count_reset = 1'b1;
-                       if(tx_start)
-                               next_state = SEND_LO;
-               end
-               SEND_LO: begin
-                       byte_count_inc = 1'b1;
-                       phy_tx_en_r = 1'b1;
-                       phy_tx_data_sel = 1'b0;
-                       next_state = SEND_HI;
-               end
-               SEND_HI: begin
-                       phy_tx_en_r = 1'b1;
-                       phy_tx_data_sel = 1'b1;
-                       if(byte_count_max)
-                               next_state = TERMINATE;
-                       else
-                               next_state = SEND_LO;
-               end
-               TERMINATE: begin
-                       byte_count_reset = 1'b1;
-                       tx_done = 1'b1;
-                       next_state = IDLE;
-               end
-       endcase
-end
-
-endmodule
diff --git a/verilog/minimac3/psync.v b/verilog/minimac3/psync.v
deleted file mode 100644 (file)
index 26597bb..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-module psync(
-       input clk1,
-       input i,
-       input clk2,
-       output o
-);
-
-reg level;
-always @(posedge clk1)
-       if(i)
-               level <= ~level;
-
-reg level1;
-reg level2;
-reg level3;
-always @(posedge clk2) begin
-       level1 <= level;
-       level2 <= level1;
-       level3 <= level2;
-end
-
-assign o = level2 ^ level3;
-
-initial begin
-       level <= 1'b0;
-       level1 <= 1'b0;
-       level2 <= 1'b0;
-       level3 <= 1'b0;
-end
-
-endmodule
index 63052eef0a8e4d9c623611dafe4443586a06a6c9..140c84835f9dffa1bb8508bbae1d024d02681f99 100644 (file)
@@ -6,13 +6,13 @@ module mxcrg #(
 ) (
        input clk50_pad,
        input trigger_reset,
-       
+
        output sys_clk,
        output reg sys_rst,
-       
+
        /* Reset NOR flash */
        output norflash_rst_n,
-       
+
        /* DDR PHY clocks */
        output clk2x_270,
        output clk4x_wr,
@@ -23,14 +23,7 @@ module mxcrg #(
        /* DDR off-chip clocking */
        output ddr_clk_pad_p,
        output ddr_clk_pad_n,
-       
-       /* Ethernet PHY clocks */
-       output reg eth_phy_clk_pad,
-       input eth_rx_clk_pad,
-       input eth_tx_clk_pad,
-       output eth_rx_clk,
-       output eth_tx_clk,
-       
+
        /* Base clock, buffered */
        output base50_clk
 );
@@ -116,27 +109,27 @@ PLL_ADV #(
        .CLKOUT0_DIVIDE(f_div),
        .CLKOUT0_DUTY_CYCLE(0.5),
        .CLKOUT0_PHASE(0.0),
-       
+
        .CLKOUT1_DIVIDE(f_div),
        .CLKOUT1_DUTY_CYCLE(0.5),
        .CLKOUT1_PHASE(0.0),
-       
+
        .CLKOUT2_DIVIDE(2*f_div),
        .CLKOUT2_DUTY_CYCLE(0.5),
        .CLKOUT2_PHASE(270.0),
-       
+
        .CLKOUT3_DIVIDE(4*f_div),
        .CLKOUT3_DUTY_CYCLE(0.5),
        .CLKOUT3_PHASE(0.0),
-       
+
        .CLKOUT4_DIVIDE(4*f_mult),
        .CLKOUT4_DUTY_CYCLE(0.5),
        .CLKOUT4_PHASE(0.0),
-       
+
        .CLKOUT5_DIVIDE(2*f_div),
        .CLKOUT5_DUTY_CYCLE(0.5),
        .CLKOUT5_PHASE(250.0),
-       
+
        .COMPENSATION("INTERNAL"),
        .DIVCLK_DIVIDE(1),
        .REF_JITTER(0.100),
@@ -218,7 +211,7 @@ BUFG bufg_x2_offclk(
 );
 
 
-/* 
+/*
  * SDRAM clock
  */
 
@@ -251,15 +244,4 @@ ODDR2 #(
        .S(1'b0)
 );
 
-/*
- * Ethernet PHY 
- */
-
-always @(posedge base50_clk)
-       eth_phy_clk_pad <= ~eth_phy_clk_pad;
-
-/* Let the synthesizer insert the appropriate buffers */
-assign eth_rx_clk = eth_rx_clk_pad;
-assign eth_tx_clk = eth_tx_clk_pad;
 endmodule