new Ethernet MAC

This commit is contained in:
Florent Kermarec 2014-11-20 16:47:11 -08:00 committed by Sebastien Bourdeauducq
parent f4d6ac8393
commit 603c2641bb
31 changed files with 1256 additions and 808 deletions

110
misoclib/ethmac/__init__.py Normal file
View File

@ -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")

View File

@ -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)
]

View File

@ -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

View File

@ -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)

123
misoclib/ethmac/phys/mii.py Normal file
View File

@ -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

145
misoclib/ethmac/preamble.py Normal file
View File

@ -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"),
)
)

251
misoclib/ethmac/sram.py Normal file
View File

@ -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)

17
misoclib/ethmac/std.py Normal file
View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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))

View File

@ -8,8 +8,6 @@ class MXCRG(Module):
self.clock_domains.cd_sdram_half = ClockDomain() self.clock_domains.cd_sdram_half = ClockDomain()
self.clock_domains.cd_sdram_full_wr = ClockDomain() self.clock_domains.cd_sdram_full_wr = ClockDomain()
self.clock_domains.cd_sdram_full_rd = 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.clock_domains.cd_base50 = ClockDomain(reset_less=True)
self.clk4x_wr_strb = Signal() self.clk4x_wr_strb = Signal()
@ -28,21 +26,15 @@ class MXCRG(Module):
Instance.Input("clk50_pad", pads.clk50), Instance.Input("clk50_pad", pads.clk50),
Instance.Input("trigger_reset", pads.trigger_reset), 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_clk", self.cd_sys.clk),
Instance.Output("sys_rst", self.cd_sys.rst), Instance.Output("sys_rst", self.cd_sys.rst),
Instance.Output("clk2x_270", self.cd_sdram_half.clk), Instance.Output("clk2x_270", self.cd_sdram_half.clk),
Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk), Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk),
Instance.Output("clk4x_rd", self.cd_sdram_full_rd.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("base50_clk", self.cd_base50.clk),
Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb), Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb),
Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb), Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb),
Instance.Output("norflash_rst_n", pads.norflash_rst_n), Instance.Output("norflash_rst_n", pads.norflash_rst_n),
Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p), Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p),
Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n), Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n))
Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk))

View File

@ -176,7 +176,7 @@ void serialboot(void)
} }
} }
#ifdef MINIMAC_BASE #ifdef ETHMAC_BASE
#define LOCALIP1 192 #define LOCALIP1 192
#define LOCALIP2 168 #define LOCALIP2 168

View File

@ -319,7 +319,7 @@ static void help(void)
puts("rcsr - read processor CSR"); puts("rcsr - read processor CSR");
puts("wcsr - write processor CSR"); puts("wcsr - write processor CSR");
#endif #endif
#ifdef MINIMAC_BASE #ifdef ETHMAC_BASE
puts("netboot - boot via TFTP"); puts("netboot - boot via TFTP");
#endif #endif
puts("serialboot - boot via SFL"); puts("serialboot - boot via SFL");
@ -361,7 +361,7 @@ static void do_command(char *c)
else if(strcmp(token, "flashboot") == 0) flashboot(); else if(strcmp(token, "flashboot") == 0) flashboot();
#endif #endif
else if(strcmp(token, "serialboot") == 0) serialboot(); else if(strcmp(token, "serialboot") == 0) serialboot();
#ifdef MINIMAC_BASE #ifdef ETHMAC_BASE
else if(strcmp(token, "netboot") == 0) netboot(); else if(strcmp(token, "netboot") == 0) netboot();
#endif #endif
@ -464,7 +464,7 @@ static int test_user_abort(void)
printf("Automatic boot in 2 seconds...\n"); printf("Automatic boot in 2 seconds...\n");
printf("Q/ESC: abort boot\n"); printf("Q/ESC: abort boot\n");
printf("F7: boot from serial\n"); printf("F7: boot from serial\n");
#ifdef MINIMAC_BASE #ifdef ETHMAC_BASE
printf("F8: boot from network\n"); printf("F8: boot from network\n");
#endif #endif
timer0_en_write(0); timer0_en_write(0);
@ -483,7 +483,7 @@ static int test_user_abort(void)
serialboot(); serialboot();
return 0; return 0;
} }
#ifdef MINIMAC_BASE #ifdef ETHMAC_BASE
if(c == 0x07) { if(c == 0x07) {
netboot(); netboot();
return 0; return 0;
@ -502,7 +502,7 @@ static void boot_sequence(void)
flashboot(); flashboot();
#endif #endif
serialboot(); serialboot();
#ifdef MINIMAC_BASE #ifdef ETHMAC_BASE
netboot(); netboot();
#endif #endif
printf("No boot medium found\n"); 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); printf("Revision %08x built "__DATE__" "__TIME__"\n\n", MSC_GIT_ID);
crcbios(); crcbios();
id_print(); id_print();
#ifdef MINIMAC_BASE #ifdef ETHMAC_BASE
ethreset(); ethreset();
#endif #endif
#ifdef DFII_BASE #ifdef DFII_BASE

View File

@ -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

View File

@ -16,9 +16,8 @@
#define DFII_COMMAND_WRDATA 0x10 #define DFII_COMMAND_WRDATA 0x10
#define DFII_COMMAND_RDDATA 0x20 #define DFII_COMMAND_RDDATA 0x20
#define MINIMAC_EV_RX0 0x1 #define ETHMAC_EV_SRAM_WRITER 0x1
#define MINIMAC_EV_RX1 0x2 #define ETHMAC_EV_SRAM_READER 0x1
#define MINIMAC_EV_TX 0x4
#define CLKGEN_STATUS_BUSY 0x1 #define CLKGEN_STATUS_BUSY 0x1
#define CLKGEN_STATUS_PROGDONE 0x2 #define CLKGEN_STATUS_PROGDONE 0x2

View File

@ -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

View File

@ -1,19 +1,25 @@
#include <generated/csr.h> #include <generated/csr.h>
#ifdef MINIMAC_BASE #ifdef ETHMAC_BASE
#include <stdio.h> #include <stdio.h>
#include <system.h> #include <system.h>
#include <crc.h> #include <crc.h>
#include <hw/flags.h> #include <hw/flags.h>
#include <hw/minimac_mem.h> #include <hw/ethmac_mem.h>
#include <net/microudp.h> #include <net/microudp.h>
#define ETHERTYPE_ARP 0x0806 #define ETHERTYPE_ARP 0x0806
#define ETHERTYPE_IP 0x0800 #define ETHERTYPE_IP 0x0800
#ifdef CSR_ETHMAC_HW_PREAMBLE_CRC_ADDR
#define HW_PREAMBLE_CRC
#endif
struct ethernet_header { struct ethernet_header {
#ifndef HW_PREAMBLE_CRC
unsigned char preamble[8]; unsigned char preamble[8];
#endif
unsigned char destmac[6]; unsigned char destmac[6];
unsigned char srcmac[6]; unsigned char srcmac[6];
unsigned short ethertype; unsigned short ethertype;
@ -23,9 +29,11 @@ static void fill_eth_header(struct ethernet_header *h, const unsigned char *dest
{ {
int i; int i;
#ifndef HW_PREAMBLE_CRC
for(i=0;i<7;i++) for(i=0;i<7;i++)
h->preamble[i] = 0x55; h->preamble[i] = 0x55;
h->preamble[7] = 0xd5; h->preamble[7] = 0xd5;
#endif
for(i=0;i<6;i++) for(i=0;i<6;i++)
h->destmac[i] = destmac[i]; h->destmac[i] = destmac[i];
for(i=0;i<6;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_HWTYPE_ETHERNET 0x0001
#define ARP_PROTO_IP 0x0800 #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_REQUEST 0x0001
#define ARP_OPCODE_REPLY 0x0002 #define ARP_OPCODE_REPLY 0x0002
@ -97,27 +110,37 @@ typedef union {
} ethernet_buffer; } ethernet_buffer;
static unsigned int rxslot;
static unsigned int rxlen; static unsigned int rxlen;
static ethernet_buffer *rxbuffer; static ethernet_buffer *rxbuffer;
static ethernet_buffer *rxbuffer0; static ethernet_buffer *rxbuffer0;
static ethernet_buffer *rxbuffer1; static ethernet_buffer *rxbuffer1;
static unsigned int txslot;
static unsigned int txlen; static unsigned int txlen;
static ethernet_buffer *txbuffer; static ethernet_buffer *txbuffer;
static ethernet_buffer *txbuffer0;
static ethernet_buffer *txbuffer1;
static void send_packet(void) static void send_packet(void)
{ {
#ifndef HW_PREAMBLE_CRC
unsigned int crc; unsigned int crc;
crc = crc32(&txbuffer->raw[8], txlen-8); crc = crc32(&txbuffer->raw[8], txlen-8);
txbuffer->raw[txlen ] = (crc & 0xff); txbuffer->raw[txlen ] = (crc & 0xff);
txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8; txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8;
txbuffer->raw[txlen+2] = (crc & 0xff0000) >> 16; txbuffer->raw[txlen+2] = (crc & 0xff0000) >> 16;
txbuffer->raw[txlen+3] = (crc & 0xff000000) >> 24; txbuffer->raw[txlen+3] = (crc & 0xff000000) >> 24;
txlen += 4; txlen += 4;
minimac_tx_count_write(txlen); #endif
minimac_tx_start_write(1); ethmac_sram_reader_slot_write(txslot);
while(!(minimac_ev_pending_read() & MINIMAC_EV_TX)); ethmac_sram_reader_length_write(txlen);
minimac_ev_pending_write(MINIMAC_EV_TX); 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]; 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; const struct arp_frame *rx_arp = &rxbuffer->frame.contents.arp;
struct arp_frame *tx_arp = &txbuffer->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->hwtype != ARP_HWTYPE_ETHERNET) return;
if(rx_arp->proto != ARP_PROTO_IP) return; if(rx_arp->proto != ARP_PROTO_IP) return;
if(rx_arp->hwsize != 6) return; if(rx_arp->hwsize != 6) return;
@ -153,7 +176,7 @@ static void process_arp(void)
rx_arp->sender_mac, rx_arp->sender_mac,
my_mac, my_mac,
ETHERTYPE_ARP); ETHERTYPE_ARP);
txlen = 68; txlen = ARP_PACKET_LENGTH;
tx_arp->hwtype = ARP_HWTYPE_ETHERNET; tx_arp->hwtype = ARP_HWTYPE_ETHERNET;
tx_arp->proto = ARP_PROTO_IP; tx_arp->proto = ARP_PROTO_IP;
tx_arp->hwsize = 6; tx_arp->hwsize = 6;
@ -194,7 +217,7 @@ int microudp_arp_resolve(unsigned int ip)
broadcast, broadcast,
my_mac, my_mac,
ETHERTYPE_ARP); ETHERTYPE_ARP);
txlen = 68; txlen = ARP_PACKET_LENGTH;
arp->hwtype = ARP_HWTYPE_ETHERNET; arp->hwtype = ARP_HWTYPE_ETHERNET;
arp->proto = ARP_PROTO_IP; arp->proto = ARP_PROTO_IP;
arp->hwsize = 6; arp->hwsize = 6;
@ -265,7 +288,7 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int
return 0; return 0;
txlen = length + sizeof(struct ethernet_header) + sizeof(struct udp_frame); 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, fill_eth_header(&txbuffer->frame.eth_header,
cached_mac, cached_mac,
@ -332,14 +355,18 @@ void microudp_set_callback(udp_callback callback)
static void process_frame(void) static void process_frame(void)
{ {
int i;
unsigned int received_crc;
unsigned int computed_crc;
flush_cpu_dcache(); flush_cpu_dcache();
#ifndef HW_PREAMBLE_CRC
int i;
for(i=0;i<7;i++) for(i=0;i<7;i++)
if(rxbuffer->frame.eth_header.preamble[i] != 0x55) return; if(rxbuffer->frame.eth_header.preamble[i] != 0x55) return;
if(rxbuffer->frame.eth_header.preamble[7] != 0xd5) 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) received_crc = ((unsigned int)rxbuffer->raw[rxlen-1] << 24)
|((unsigned int)rxbuffer->raw[rxlen-2] << 16) |((unsigned int)rxbuffer->raw[rxlen-2] << 16)
|((unsigned int)rxbuffer->raw[rxlen-3] << 8) |((unsigned int)rxbuffer->raw[rxlen-3] << 8)
@ -348,6 +375,8 @@ static void process_frame(void)
if(received_crc != computed_crc) return; if(received_crc != computed_crc) return;
rxlen -= 4; /* strip CRC here to be consistent with TX */ rxlen -= 4; /* strip CRC here to be consistent with TX */
#endif
if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_ARP) process_arp(); if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_ARP) process_arp();
else if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_IP) process_ip(); 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) void microudp_start(const unsigned char *macaddr, unsigned int ip)
{ {
int i; int i;
ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER);
ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER);
minimac_ev_pending_write(MINIMAC_EV_RX0 | MINIMAC_EV_RX1 | MINIMAC_EV_TX); rxbuffer0 = (ethernet_buffer *)ETHMAC_RX0_BASE;
rxbuffer1 = (ethernet_buffer *)ETHMAC_RX1_BASE;
txbuffer0 = (ethernet_buffer *)ETHMAC_TX0_BASE;
txbuffer1 = (ethernet_buffer *)ETHMAC_TX1_BASE;
rxbuffer0 = (ethernet_buffer *)MINIMAC_RX0_BASE; rxslot = 0;
rxbuffer1 = (ethernet_buffer *)MINIMAC_RX1_BASE; txslot = 0;
txbuffer = (ethernet_buffer *)MINIMAC_TX_BASE;
rxbuffer = rxbuffer0;
txbuffer = txbuffer0;
for(i=0;i<6;i++) for(i=0;i<6;i++)
my_mac[i] = macaddr[i]; my_mac[i] = macaddr[i];
@ -375,17 +411,15 @@ void microudp_start(const unsigned char *macaddr, unsigned int ip)
void microudp_service(void) void microudp_service(void)
{ {
if(minimac_ev_pending_read() & MINIMAC_EV_RX0) { if(ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER) {
rxlen = minimac_rx_count_0_read(); rxslot = ethmac_sram_writer_slot_read();
rxbuffer = rxbuffer0; rxlen = ethmac_sram_writer_length_read();
if (rxslot)
rxbuffer = rxbuffer1;
else
rxbuffer = rxbuffer0;
process_frame(); process_frame();
minimac_ev_pending_write(MINIMAC_EV_RX0); ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER);
}
if(minimac_ev_pending_read() & MINIMAC_EV_RX1) {
rxlen = minimac_rx_count_1_read();
rxbuffer = rxbuffer1;
process_frame();
minimac_ev_pending_write(MINIMAC_EV_RX1);
} }
} }
@ -401,12 +435,12 @@ static void busy_wait(unsigned int ds)
void ethreset(void) void ethreset(void)
{ {
minimac_phy_reset_write(0); ethphy_crg_reset_write(0);
busy_wait(2); busy_wait(2);
/* that pesky ethernet PHY needs two resets at times... */ /* that pesky ethernet PHY needs two resets at times... */
minimac_phy_reset_write(1); ethphy_crg_reset_write(1);
busy_wait(2); busy_wait(2);
minimac_phy_reset_write(0); ethphy_crg_reset_write(0);
busy_wait(2); busy_wait(2);
} }

View File

@ -90,6 +90,7 @@ static void rx_callback(uint32_t src_ip, uint16_t src_port,
if(length < BLOCK_SIZE) if(length < BLOCK_SIZE)
transfer_finished = 1; transfer_finished = 1;
packet_data = microudp_get_tx_buffer();
length = format_ack(packet_data, block); length = format_ack(packet_data, block);
microudp_send(PORT_IN, src_port, length); microudp_send(PORT_IN, src_port, length);
} }
@ -111,13 +112,13 @@ int tftp_get(uint32_t ip, const char *filename, void *buffer)
microudp_set_callback(rx_callback); microudp_set_callback(rx_callback);
packet_data = microudp_get_tx_buffer();
dst_buffer = buffer; dst_buffer = buffer;
total_length = 0; total_length = 0;
transfer_finished = 0; transfer_finished = 0;
tries = 5; tries = 5;
while(1) { while(1) {
packet_data = microudp_get_tx_buffer();
len = format_request(packet_data, TFTP_RRQ, filename); len = format_request(packet_data, TFTP_RRQ, filename);
microudp_send(PORT_IN, PORT_OUT, len); microudp_send(PORT_IN, PORT_OUT, len);
for(i=0;i<2000000;i++) { for(i=0;i<2000000;i++) {
@ -168,6 +169,7 @@ int tftp_put(uint32_t ip, const char *filename, const void *buffer, int size)
transfer_finished = 0; transfer_finished = 0;
tries = 5; tries = 5;
while(1) { while(1) {
packet_data = microudp_get_tx_buffer();
len = format_request(packet_data, TFTP_WRQ, filename); len = format_request(packet_data, TFTP_WRQ, filename);
microudp_send(PORT_IN, PORT_OUT, len); microudp_send(PORT_IN, PORT_OUT, len);
for(i=0;i<2000000;i++) { for(i=0;i<2000000;i++) {
@ -189,6 +191,7 @@ send_data:
send = sent+BLOCK_SIZE > size ? size-sent : BLOCK_SIZE; send = sent+BLOCK_SIZE > size ? size-sent : BLOCK_SIZE;
tries = 5; tries = 5;
while(1) { while(1) {
packet_data = microudp_get_tx_buffer();
len = format_data(packet_data, block, buffer, send); len = format_data(packet_data, block, buffer, send);
microudp_send(PORT_IN, data_port, len); microudp_send(PORT_IN, data_port, len);
for(i=0;i<12000000;i++) { for(i=0;i<12000000;i++) {

View File

@ -1,9 +1,10 @@
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer
from misoclib import lasmicon, spiflash from misoclib import lasmicon, spiflash, ethmac
from misoclib.sdramphy import k7ddrphy from misoclib.sdramphy import k7ddrphy
from misoclib.gensoc import SDRAMSoC from misoclib.gensoc import SDRAMSoC
from misoclib.ethmac.phys import gmii
class _CRG(Module): class _CRG(Module):
def __init__(self, platform): def __init__(self, platform):
@ -104,4 +105,24 @@ class BaseSoC(SDRAMSoC):
self.flash_boot_address = 0xb00000 self.flash_boot_address = 0xb00000
self.register_rom(self.spiflash.bus) 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 default_subtarget = BaseSoC

View File

@ -4,9 +4,10 @@ from fractions import Fraction
from migen.fhdl.std import * from migen.fhdl.std import *
from mibuild.generic_platform import ConstraintError 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.sdramphy import s6ddrphy
from misoclib.gensoc import SDRAMSoC from misoclib.gensoc import SDRAMSoC
from misoclib.ethmac.phys import mii
class _MXClockPads: class _MXClockPads:
def __init__(self, platform): def __init__(self, platform):
@ -20,10 +21,6 @@ class _MXClockPads:
ddram_clock = platform.request("ddram_clock") ddram_clock = platform.request("ddram_clock")
self.ddr_clk_p = ddram_clock.p self.ddr_clk_p = ddram_clock.p
self.ddr_clk_n = ddram_clock.n 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): class BaseSoC(SDRAMSoC):
default_platform = "mixxeo" # also supports m1 default_platform = "mixxeo" # also supports m1
@ -75,12 +72,13 @@ PIN "mxcrg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE;
class MiniSoC(BaseSoC): class MiniSoC(BaseSoC):
csr_map = { csr_map = {
"minimac": 10, "ethphy": 10,
"ethmac": 11,
} }
csr_map.update(BaseSoC.csr_map) csr_map.update(BaseSoC.csr_map)
interrupt_map = { interrupt_map = {
"minimac": 2, "ethmac": 2,
} }
interrupt_map.update(BaseSoC.interrupt_map) 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.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.leds = gpio.GPIOOut(Cat(platform.request("user_led", i) for i in range(2)))
self.submodules.minimac = minimac3.MiniMAC(platform.request("eth")) self.submodules.ethphy = mii.MIIPHY(platform.request("eth_clocks"), platform.request("eth"))
self.add_wb_slave(lambda a: a[26:29] == 3, self.minimac.membus) self.submodules.ethmac = ethmac.EthMAC(phy=self.ethphy, with_hw_preamble_crc=False)
self.add_cpu_memory_region("minimac_mem", 0xb0000000, 0x1800) self.add_wb_slave(lambda a: a[26:29] == 3, self.ethmac.bus)
platform.add_source_dir(os.path.join("verilog", "minimac3")) self.add_cpu_memory_region("ethmac_mem", 0xb0000000, 0x2000)
def get_vga_dvi(platform): def get_vga_dvi(platform):
try: try:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -24,13 +24,6 @@ module mxcrg #(
output ddr_clk_pad_p, output ddr_clk_pad_p,
output ddr_clk_pad_n, 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 */ /* Base clock, buffered */
output base50_clk output base50_clk
); );
@ -251,15 +244,4 @@ ODDR2 #(
.S(1'b0) .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 endmodule