new Ethernet MAC
This commit is contained in:
parent
f4d6ac8393
commit
603c2641bb
|
@ -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")
|
|
@ -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)
|
||||||
|
]
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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"),
|
||||||
|
)
|
||||||
|
)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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))
|
|
|
@ -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))
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -258,7 +258,7 @@ void flashboot(void)
|
||||||
printf("Error: Invalid flash boot image length 0x%08x\n", length);
|
printf("Error: Invalid flash boot image length 0x%08x\n", length);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Loading %d bytes from flash...\n", length);
|
printf("Loading %d bytes from flash...\n", length);
|
||||||
memcpy((void *)SDRAM_BASE, flashbase, length);
|
memcpy((void *)SDRAM_BASE, flashbase, length);
|
||||||
got_crc = crc32((unsigned char *)SDRAM_BASE, length);
|
got_crc = crc32((unsigned char *)SDRAM_BASE, length);
|
||||||
|
|
|
@ -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,10 +361,10 @@ 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
|
||||||
|
|
||||||
else if(strcmp(token, "revision") == 0) printf("%08x\n", MSC_GIT_ID);
|
else if(strcmp(token, "revision") == 0) printf("%08x\n", MSC_GIT_ID);
|
||||||
|
|
||||||
else if(strcmp(token, "help") == 0) help();
|
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, "rcsr") == 0) rcsr(get_token(&c));
|
||||||
else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c));
|
else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DFII_BASE
|
#ifdef DFII_BASE
|
||||||
else if(strcmp(token, "sdrrow") == 0) sdrrow(get_token(&c));
|
else if(strcmp(token, "sdrrow") == 0) sdrrow(get_token(&c));
|
||||||
else if(strcmp(token, "sdrsw") == 0) sdrsw();
|
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, "memtest") == 0) memtest();
|
||||||
else if(strcmp(token, "sdrinit") == 0) sdrinit();
|
else if(strcmp(token, "sdrinit") == 0) sdrinit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
else if(strcmp(token, "dfs") == 0) dfs(get_token(&c));
|
else if(strcmp(token, "dfs") == 0) dfs(get_token(&c));
|
||||||
|
|
||||||
else if(strcmp(token, "") != 0)
|
else if(strcmp(token, "") != 0)
|
||||||
|
@ -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
|
||||||
|
@ -534,7 +534,7 @@ int main(int i, char **c)
|
||||||
boot_sequence();
|
boot_sequence();
|
||||||
else
|
else
|
||||||
printf("Memory initialization failed\n");
|
printf("Memory initialization failed\n");
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
putsnonl("\e[1mBIOS>\e[0m ");
|
putsnonl("\e[1mBIOS>\e[0m ");
|
||||||
readstr(buffer, 64);
|
readstr(buffer, 64);
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
|
@ -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;
|
||||||
|
@ -148,12 +171,12 @@ static void process_arp(void)
|
||||||
if(rx_arp->opcode == ARP_OPCODE_REQUEST) {
|
if(rx_arp->opcode == ARP_OPCODE_REQUEST) {
|
||||||
if(rx_arp->target_ip == my_ip) {
|
if(rx_arp->target_ip == my_ip) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
fill_eth_header(&txbuffer->frame.eth_header,
|
fill_eth_header(&txbuffer->frame.eth_header,
|
||||||
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;
|
||||||
|
@ -259,19 +282,19 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int
|
||||||
{
|
{
|
||||||
struct pseudo_header h;
|
struct pseudo_header h;
|
||||||
unsigned int r;
|
unsigned int r;
|
||||||
|
|
||||||
if((cached_mac[0] == 0) && (cached_mac[1] == 0) && (cached_mac[2] == 0)
|
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))
|
&& (cached_mac[3] == 0) && (cached_mac[4] == 0) && (cached_mac[5] == 0))
|
||||||
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,
|
||||||
my_mac,
|
my_mac,
|
||||||
ETHERTYPE_IP);
|
ETHERTYPE_IP);
|
||||||
|
|
||||||
txbuffer->frame.contents.udp.ip.version = IP_IPV4;
|
txbuffer->frame.contents.udp.ip.version = IP_IPV4;
|
||||||
txbuffer->frame.contents.udp.ip.diff_services = 0;
|
txbuffer->frame.contents.udp.ip.diff_services = 0;
|
||||||
txbuffer->frame.contents.udp.ip.total_length = length + sizeof(struct udp_frame);
|
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,
|
r = ip_checksum(r, &txbuffer->frame.contents.udp.udp,
|
||||||
sizeof(struct udp_header)+length, 1);
|
sizeof(struct udp_header)+length, 1);
|
||||||
txbuffer->frame.contents.udp.udp.checksum = r;
|
txbuffer->frame.contents.udp.udp.checksum = r;
|
||||||
|
|
||||||
send_packet();
|
send_packet();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -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;
|
||||||
rxbuffer0 = (ethernet_buffer *)MINIMAC_RX0_BASE;
|
txbuffer0 = (ethernet_buffer *)ETHMAC_TX0_BASE;
|
||||||
rxbuffer1 = (ethernet_buffer *)MINIMAC_RX1_BASE;
|
txbuffer1 = (ethernet_buffer *)ETHMAC_TX1_BASE;
|
||||||
txbuffer = (ethernet_buffer *)MINIMAC_TX_BASE;
|
|
||||||
|
rxslot = 0;
|
||||||
|
txslot = 0;
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ static void rx_callback(uint32_t src_ip, uint16_t src_port,
|
||||||
uint16_t block;
|
uint16_t block;
|
||||||
int i;
|
int i;
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
if(length < 4) return;
|
if(length < 4) return;
|
||||||
if(dst_port != PORT_IN) return;
|
if(dst_port != PORT_IN) return;
|
||||||
opcode = data[0] << 8 | data[1];
|
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;
|
total_length += length;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -105,19 +106,19 @@ int tftp_get(uint32_t ip, const char *filename, void *buffer)
|
||||||
int tries;
|
int tries;
|
||||||
int i;
|
int i;
|
||||||
int length_before;
|
int length_before;
|
||||||
|
|
||||||
if(!microudp_arp_resolve(ip))
|
if(!microudp_arp_resolve(ip))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
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++) {
|
||||||
|
@ -156,7 +157,7 @@ int tftp_put(uint32_t ip, const char *filename, const void *buffer, int size)
|
||||||
int tries;
|
int tries;
|
||||||
int i;
|
int i;
|
||||||
int block = 0, sent = 0;
|
int block = 0, sent = 0;
|
||||||
|
|
||||||
if(!microudp_arp_resolve(ip))
|
if(!microudp_arp_resolve(ip))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -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++) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -6,13 +6,13 @@ module mxcrg #(
|
||||||
) (
|
) (
|
||||||
input clk50_pad,
|
input clk50_pad,
|
||||||
input trigger_reset,
|
input trigger_reset,
|
||||||
|
|
||||||
output sys_clk,
|
output sys_clk,
|
||||||
output reg sys_rst,
|
output reg sys_rst,
|
||||||
|
|
||||||
/* Reset NOR flash */
|
/* Reset NOR flash */
|
||||||
output norflash_rst_n,
|
output norflash_rst_n,
|
||||||
|
|
||||||
/* DDR PHY clocks */
|
/* DDR PHY clocks */
|
||||||
output clk2x_270,
|
output clk2x_270,
|
||||||
output clk4x_wr,
|
output clk4x_wr,
|
||||||
|
@ -23,14 +23,7 @@ module mxcrg #(
|
||||||
/* DDR off-chip clocking */
|
/* DDR off-chip clocking */
|
||||||
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
|
||||||
);
|
);
|
||||||
|
@ -116,27 +109,27 @@ PLL_ADV #(
|
||||||
.CLKOUT0_DIVIDE(f_div),
|
.CLKOUT0_DIVIDE(f_div),
|
||||||
.CLKOUT0_DUTY_CYCLE(0.5),
|
.CLKOUT0_DUTY_CYCLE(0.5),
|
||||||
.CLKOUT0_PHASE(0.0),
|
.CLKOUT0_PHASE(0.0),
|
||||||
|
|
||||||
.CLKOUT1_DIVIDE(f_div),
|
.CLKOUT1_DIVIDE(f_div),
|
||||||
.CLKOUT1_DUTY_CYCLE(0.5),
|
.CLKOUT1_DUTY_CYCLE(0.5),
|
||||||
.CLKOUT1_PHASE(0.0),
|
.CLKOUT1_PHASE(0.0),
|
||||||
|
|
||||||
.CLKOUT2_DIVIDE(2*f_div),
|
.CLKOUT2_DIVIDE(2*f_div),
|
||||||
.CLKOUT2_DUTY_CYCLE(0.5),
|
.CLKOUT2_DUTY_CYCLE(0.5),
|
||||||
.CLKOUT2_PHASE(270.0),
|
.CLKOUT2_PHASE(270.0),
|
||||||
|
|
||||||
.CLKOUT3_DIVIDE(4*f_div),
|
.CLKOUT3_DIVIDE(4*f_div),
|
||||||
.CLKOUT3_DUTY_CYCLE(0.5),
|
.CLKOUT3_DUTY_CYCLE(0.5),
|
||||||
.CLKOUT3_PHASE(0.0),
|
.CLKOUT3_PHASE(0.0),
|
||||||
|
|
||||||
.CLKOUT4_DIVIDE(4*f_mult),
|
.CLKOUT4_DIVIDE(4*f_mult),
|
||||||
.CLKOUT4_DUTY_CYCLE(0.5),
|
.CLKOUT4_DUTY_CYCLE(0.5),
|
||||||
.CLKOUT4_PHASE(0.0),
|
.CLKOUT4_PHASE(0.0),
|
||||||
|
|
||||||
.CLKOUT5_DIVIDE(2*f_div),
|
.CLKOUT5_DIVIDE(2*f_div),
|
||||||
.CLKOUT5_DUTY_CYCLE(0.5),
|
.CLKOUT5_DUTY_CYCLE(0.5),
|
||||||
.CLKOUT5_PHASE(250.0),
|
.CLKOUT5_PHASE(250.0),
|
||||||
|
|
||||||
.COMPENSATION("INTERNAL"),
|
.COMPENSATION("INTERNAL"),
|
||||||
.DIVCLK_DIVIDE(1),
|
.DIVCLK_DIVIDE(1),
|
||||||
.REF_JITTER(0.100),
|
.REF_JITTER(0.100),
|
||||||
|
@ -218,7 +211,7 @@ BUFG bufg_x2_offclk(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SDRAM clock
|
* SDRAM clock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue