From 603c2641bb9b1c7018235afbc4b45c2e3c4f8dab Mon Sep 17 00:00:00 2001 From: Florent Kermarec Date: Thu, 20 Nov 2014 16:47:11 -0800 Subject: [PATCH] new Ethernet MAC --- misoclib/ethmac/__init__.py | 110 ++++++++++++ misoclib/ethmac/last_be.py | 37 ++++ misoclib/ethmac/phys/gmii.py | 71 ++++++++ misoclib/ethmac/phys/loopback.py | 32 ++++ misoclib/ethmac/phys/mii.py | 123 ++++++++++++++ misoclib/ethmac/preamble.py | 145 ++++++++++++++++ misoclib/ethmac/sram.py | 251 ++++++++++++++++++++++++++++ misoclib/ethmac/std.py | 17 ++ misoclib/ethmac/test/Makefile | 13 ++ misoclib/ethmac/test/__init__.py | 53 ++++++ misoclib/ethmac/test/crc_tb.py | 61 +++++++ misoclib/ethmac/test/ethmac_tb.py | 134 +++++++++++++++ misoclib/ethmac/test/preamble_tb.py | 61 +++++++ misoclib/minimac3/__init__.py | 81 --------- misoclib/mxcrg/__init__.py | 10 +- software/bios/boot.c | 4 +- software/bios/main.c | 20 +-- software/include/hw/ethmac_mem.h | 11 ++ software/include/hw/flags.h | 5 +- software/include/hw/minimac_mem.h | 10 -- software/libnet/microudp.c | 110 +++++++----- software/libnet/tftp.c | 13 +- targets/kc705.py | 23 ++- targets/mlabs_video.py | 20 +-- verilog/minimac3/minimac3.v | 138 --------------- verilog/minimac3/minimac3_memory.v | 152 ----------------- verilog/minimac3/minimac3_rx.v | 129 -------------- verilog/minimac3/minimac3_sync.v | 76 --------- verilog/minimac3/minimac3_tx.v | 83 --------- verilog/minimac3/psync.v | 31 ---- verilog/mxcrg/mxcrg.v | 40 ++--- 31 files changed, 1256 insertions(+), 808 deletions(-) create mode 100644 misoclib/ethmac/__init__.py create mode 100644 misoclib/ethmac/last_be.py create mode 100644 misoclib/ethmac/phys/gmii.py create mode 100644 misoclib/ethmac/phys/loopback.py create mode 100644 misoclib/ethmac/phys/mii.py create mode 100644 misoclib/ethmac/preamble.py create mode 100644 misoclib/ethmac/sram.py create mode 100644 misoclib/ethmac/std.py create mode 100644 misoclib/ethmac/test/Makefile create mode 100644 misoclib/ethmac/test/__init__.py create mode 100644 misoclib/ethmac/test/crc_tb.py create mode 100644 misoclib/ethmac/test/ethmac_tb.py create mode 100644 misoclib/ethmac/test/preamble_tb.py delete mode 100644 misoclib/minimac3/__init__.py create mode 100644 software/include/hw/ethmac_mem.h delete mode 100644 software/include/hw/minimac_mem.h delete mode 100644 verilog/minimac3/minimac3.v delete mode 100644 verilog/minimac3/minimac3_memory.v delete mode 100644 verilog/minimac3/minimac3_rx.v delete mode 100644 verilog/minimac3/minimac3_sync.v delete mode 100644 verilog/minimac3/minimac3_tx.v delete mode 100644 verilog/minimac3/psync.v diff --git a/misoclib/ethmac/__init__.py b/misoclib/ethmac/__init__.py new file mode 100644 index 00000000..73b1a171 --- /dev/null +++ b/misoclib/ethmac/__init__.py @@ -0,0 +1,110 @@ +# This file is Copyright (c) 2014 Florent Kermarrec +# License: BSD + +from migen.fhdl.std import * + +from migen.bus import wishbone +from migen.actorlib.fifo import AsyncFIFO +from migen.actorlib.structuring import Converter, Pipeline +from migen.bank.eventmanager import SharedIRQ +from migen.bank.description import * +from migen.fhdl.simplify import * + +from misoclib.ethmac.std import * +from misoclib.ethmac.preamble import PreambleInserter, PreambleChecker +from migen.actorlib.crc import CRC32Inserter, CRC32Checker +from misoclib.ethmac.last_be import TXLastBE, RXLastBE +from misoclib.ethmac.sram import SRAMWriter, SRAMReader + +class EthMAC(Module, AutoCSR): + def __init__(self, phy, interface="wishbone", with_hw_preamble_crc=True, endianness="be"): + # Preamble / CRC (optional) + if with_hw_preamble_crc: + self._hw_preamble_crc = CSRStatus(reset=1) + # Preamble insert/check + preamble_inserter = PreambleInserter(phy.dw) + preamble_checker = PreambleChecker(phy.dw) + self.submodules += RenameClockDomains(preamble_inserter, "eth_tx") + self.submodules += RenameClockDomains(preamble_checker, "eth_rx") + + # CRC insert/check + crc32_inserter = CRC32Inserter(eth_description(phy.dw)) + crc32_checker = CRC32Checker(eth_description(phy.dw)) + self.submodules += RenameClockDomains(crc32_inserter, "eth_tx") + self.submodules += RenameClockDomains(crc32_checker, "eth_rx") + + # Delimiters + tx_last_be = TXLastBE(phy.dw) + rx_last_be = RXLastBE(phy.dw) + self.submodules += RenameClockDomains(tx_last_be, "eth_tx") + self.submodules += RenameClockDomains(rx_last_be, "eth_rx") + + # Converters + reverse = endianness == "be" + tx_converter = Converter(eth_description(32), eth_description(phy.dw), reverse=reverse) + rx_converter = Converter(eth_description(phy.dw), eth_description(32), reverse=reverse) + self.submodules += RenameClockDomains(tx_converter, "eth_tx") + self.submodules += RenameClockDomains(rx_converter, "eth_rx") + + # Cross Domain Crossing + tx_cdc = AsyncFIFO(eth_description(32), 4) + rx_cdc = AsyncFIFO(eth_description(32), 4) + self.submodules += RenameClockDomains(tx_cdc, {"write": "sys", "read": "eth_tx"}) + self.submodules += RenameClockDomains(rx_cdc, {"write": "eth_rx", "read": "sys"}) + + # Graph + if with_hw_preamble_crc: + rx_pipeline = [phy, preamble_checker, crc32_checker, rx_last_be, rx_converter, rx_cdc] + tx_pipeline = [tx_cdc, tx_converter, tx_last_be, crc32_inserter, preamble_inserter, phy] + else: + rx_pipeline = [phy, rx_last_be, rx_converter, rx_cdc] + tx_pipeline = [tx_cdc, tx_converter, tx_last_be, phy] + self.submodules.rx_pipeline = Pipeline(*rx_pipeline) + self.submodules.tx_pipeline = Pipeline(*tx_pipeline) + + if interface == "wishbone": + nrxslots=2 + ntxslots=2 + + self.bus = wishbone.Interface() + + # SRAM Memories + sram_depth = buffer_depth//(32//8) + self.submodules.sram_writer = SRAMWriter(sram_depth, nrxslots) + self.submodules.sram_reader = SRAMReader(sram_depth, ntxslots) + self.submodules.ev = SharedIRQ(self.sram_writer.ev, self.sram_reader.ev) + + # Connect to pipelines + self.comb += [ + self.rx_pipeline.source.connect(self.sram_writer.sink), + self.sram_reader.source.connect(self.tx_pipeline.sink) + ] + + # Interface + wb_rx_sram_ifs = [wishbone.SRAM(self.sram_writer.mems[n], read_only=True) + for n in range(nrxslots)] + wb_tx_sram_ifs = [FullMemoryWE(wishbone.SRAM(self.sram_reader.mems[n], read_only=False)) + for n in range(ntxslots)] + wb_sram_ifs = wb_rx_sram_ifs + wb_tx_sram_ifs + + wb_slaves = [] + decoderoffset = log2_int(sram_depth) + decoderbits = log2_int(len(wb_sram_ifs)) + for n, wb_sram_if in enumerate(wb_sram_ifs): + def slave_filter(a, v=n): + return a[decoderoffset:decoderoffset+decoderbits] == v + wb_slaves.append((slave_filter, wb_sram_if.bus)) + self.submodules += wb_sram_if + wb_con = wishbone.Decoder(self.bus, wb_slaves, register=True) + self.submodules += wb_con + + elif interface == "lasmi": + raise NotImplementedError + + elif interface == "expose": + # expose pipelines endpoints + self.sink = tx_pipeline.sink + self.source = rx_pipeline.source + + else: + raise ValueError("EthMAC only supports Wishbone, LASMI or expose interfaces") diff --git a/misoclib/ethmac/last_be.py b/misoclib/ethmac/last_be.py new file mode 100644 index 00000000..e7fbf2ae --- /dev/null +++ b/misoclib/ethmac/last_be.py @@ -0,0 +1,37 @@ +from migen.fhdl.std import * +from migen.genlib.record import * +from migen.flow.actor import Sink, Source + +from misoclib.ethmac.std import * + +class TXLastBE(Module): + def __init__(self, d_w): + self.sink = sink = Sink(eth_description(d_w)) + self.source = source = Source(eth_description(d_w)) + ### + ongoing = Signal() + self.sync += \ + If(self.sink.stb & self.sink.ack, + If(sink.sop, + ongoing.eq(1) + ).Elif(sink.last_be, + ongoing.eq(0) + ) + ) + self.comb += [ + Record.connect(self.sink, self.source), + self.source.eop.eq(self.sink.last_be), + self.source.stb.eq(self.sink.stb & (self.sink.sop | ongoing)) + ] + +class RXLastBE(Module): + def __init__(self, d_w): + self.sink = sink = Sink(eth_description(d_w)) + self.source = source = Source(eth_description(d_w)) + ### + fake = Signal() # to use RenameClockDomain + self.sync += fake.eq(1) + self.comb += [ + Record.connect(self.sink, self.source), + self.source.last_be.eq(self.sink.eop) + ] diff --git a/misoclib/ethmac/phys/gmii.py b/misoclib/ethmac/phys/gmii.py new file mode 100644 index 00000000..f4a8210e --- /dev/null +++ b/misoclib/ethmac/phys/gmii.py @@ -0,0 +1,71 @@ +from migen.fhdl.std import * +from migen.flow.actor import Sink, Source +from migen.bank.description import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from misoclib.ethmac.std import * + +class GMIIPHYTX(Module): + def __init__(self, pads): + self.sink = sink = Sink(eth_description(8)) + ### + self.sync += [ + pads.tx_er.eq(0), + pads.tx_en.eq(sink.stb), + pads.tx_data.eq(sink.d) + ] + self.comb += sink.ack.eq(1) + +class GMIIPHYRX(Module): + def __init__(self, pads): + self.source = source = Source(eth_description(8)) + ### + dv_d = Signal() + self.sync += dv_d.eq(pads.dv) + + sop = Signal() + eop = Signal() + self.comb += [ + sop.eq(pads.dv & ~dv_d), + eop.eq(~pads.dv & dv_d) + ] + self.sync += [ + source.stb.eq(pads.dv), + source.sop.eq(sop), + source.d.eq(pads.rx_data) + ] + self.comb += source.eop.eq(eop) + +# CRG is the only Xilinx specific module. +# Todo: use generic code or add support for others vendors +class GMIIPHYCRG(Module, AutoCSR): + def __init__(self, clock_pads, pads): + self._reset = CSRStorage() + ### + self.clock_domains.cd_eth_rx = ClockDomain() + self.clock_domains.cd_eth_tx = ClockDomain() + self.specials += [ + Instance("ODDR", + p_DDR_CLK_EDGE="SAME_EDGE", + i_C=ClockSignal("eth_tx"), i_CE=1, i_S=0, i_R=0, + i_D1=1, i_D2=0, o_Q=clock_pads.gtx, + ), + Instance("BUFG", i_I=clock_pads.rx, o_O=self.cd_eth_rx.clk), + ] + self.comb += self.cd_eth_tx.clk.eq(self.cd_eth_rx.clk) + + reset = self._reset.storage + self.comb += pads.rst_n.eq(~reset) + self.specials += [ + AsyncResetSynchronizer(self.cd_eth_tx, reset), + AsyncResetSynchronizer(self.cd_eth_rx, reset), + ] + +class GMIIPHY(Module, AutoCSR): + def __init__(self, clock_pads, pads): + self.dw = 8 + ### + self.submodules.crg = GMIIPHYCRG(clock_pads, pads) + self.submodules.tx = RenameClockDomains(GMIIPHYTX(pads), "eth_tx") + self.submodules.rx = RenameClockDomains(GMIIPHYRX(pads), "eth_rx") + self.sink, self.source = self.tx.sink, self.rx.source diff --git a/misoclib/ethmac/phys/loopback.py b/misoclib/ethmac/phys/loopback.py new file mode 100644 index 00000000..9e8d83c3 --- /dev/null +++ b/misoclib/ethmac/phys/loopback.py @@ -0,0 +1,32 @@ +from migen.fhdl.std import * +from migen.flow.actor import Sink, Source +from migen.bank.description import * +from migen.genlib.record import * + +from misoclib.ethmac.std import * + +class LoopbackPHYCRG(Module, AutoCSR): + def __init__(self): + self._reset = CSRStorage() + ### + self.clock_domains.cd_eth_rx = ClockDomain() + self.clock_domains.cd_eth_tx = ClockDomain() + self.comb += [ + self.cd_eth_rx.clk.eq(ClockSignal()), + self.cd_eth_tx.clk.eq(ClockSignal()) + ] + + reset = self._reset.storage + self.comb += [ + self.cd_eth_rx.rst.eq(reset), + self.cd_eth_tx.rst.eq(reset) + ] + +class LoopbackPHY(Module, AutoCSR): + def __init__(self): + self.dw = 8 + ### + self.submodules.crg = LoopbackPHYCRG() + self.sink = sink = Sink(eth_description(8)) + self.source = source = Source(eth_description(8)) + self.comb += Record.connect(self.sink, self.source) diff --git a/misoclib/ethmac/phys/mii.py b/misoclib/ethmac/phys/mii.py new file mode 100644 index 00000000..5dba08cf --- /dev/null +++ b/misoclib/ethmac/phys/mii.py @@ -0,0 +1,123 @@ +from migen.fhdl.std import * +from migen.genlib.fsm import FSM, NextState +from migen.flow.actor import Sink, Source +from migen.bank.description import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from misoclib.ethmac.std import * + +class MIIPHYTX(Module): + def __init__(self, pads): + self.sink = sink = Sink(eth_description(8)) + ### + tx_en_r = Signal() + tx_data_r = Signal(4) + self.sync += [ + pads.tx_er.eq(0), + pads.tx_en.eq(tx_en_r), + pads.tx_data.eq(tx_data_r), + ] + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("SEND_LO") + ) + ) + fsm.act("SEND_LO", + tx_data_r.eq(sink.d[0:4]), + tx_en_r.eq(1), + NextState("SEND_HI") + ) + fsm.act("SEND_HI", + tx_data_r.eq(sink.d[4:8]), + tx_en_r.eq(1), + sink.ack.eq(1), + If(sink.stb & sink.eop, + NextState("IDLE") + ).Else( + NextState("SEND_LO") + ) + ) + +class MIIPHYRX(Module): + def __init__(self, pads): + self.source = source = Source(eth_description(8)) + ### + sop = source.sop + set_sop = Signal() + clr_sop = Signal() + self.sync += \ + If(clr_sop, + sop.eq(0) + ).Elif(set_sop, + sop.eq(1) + ) + + lo = Signal(4) + hi = Signal(4) + load_nibble = Signal(2) + self.sync += \ + If(load_nibble[0], + lo.eq(pads.rx_data) + ).Elif(load_nibble[1], + hi.eq(pads.rx_data) + ) + self.comb += [ + source.d.eq(Cat(lo, hi)) + ] + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + fsm.act("IDLE", + set_sop.eq(1), + If(pads.dv, + load_nibble.eq(0b01), + NextState("LOAD_HI") + ) + ) + fsm.act("LOAD_LO", + source.stb.eq(1), + If(pads.dv, + clr_sop.eq(1), + load_nibble.eq(0b01), + NextState("LOAD_HI") + ).Else( + source.eop.eq(1), + NextState("IDLE") + ) + ) + fsm.act("LOAD_HI", + load_nibble.eq(0b10), + NextState("LOAD_LO") + ) + +class MIIPHYCRG(Module, AutoCSR): + def __init__(self, clock_pads, pads): + self._reset = CSRStorage() + ### + self.sync.base50 += clock_pads.phy.eq(~clock_pads.phy) + + self.clock_domains.cd_eth_rx = ClockDomain() + self.clock_domains.cd_eth_tx = ClockDomain() + self.comb += self.cd_eth_rx.clk.eq(clock_pads.rx) + self.comb += self.cd_eth_tx.clk.eq(clock_pads.tx) + + reset = self._reset.storage + self.comb += pads.rst_n.eq(~reset) + self.specials += [ + AsyncResetSynchronizer(self.cd_eth_tx, reset), + AsyncResetSynchronizer(self.cd_eth_rx, reset), + ] + +class MIIPHY(Module, AutoCSR): + def __init__(self, clock_pads, pads): + self.dw = 8 + ### + self.submodules.crg = MIIPHYCRG(clock_pads, pads) + self.submodules.tx = RenameClockDomains(MIIPHYTX(pads), "eth_tx") + self.submodules.rx = RenameClockDomains(MIIPHYRX(pads), "eth_rx") + self.sink, self.source = self.tx.sink, self.rx.source diff --git a/misoclib/ethmac/preamble.py b/misoclib/ethmac/preamble.py new file mode 100644 index 00000000..db693b4a --- /dev/null +++ b/misoclib/ethmac/preamble.py @@ -0,0 +1,145 @@ +from migen.fhdl.std import * +from migen.genlib.fsm import FSM, NextState +from migen.genlib.misc import chooser +from migen.genlib.record import * +from migen.flow.actor import Sink, Source + +from misoclib.ethmac.std import * + +class PreambleInserter(Module): + def __init__(self, d_w): + self.sink = Sink(eth_description(d_w)) + self.source = Source(eth_description(d_w)) + + ### + + preamble = Signal(64, reset=eth_preamble) + cnt_max = (64//d_w)-1 + cnt = Signal(max=cnt_max+1) + clr_cnt = Signal() + inc_cnt = Signal() + + self.sync += \ + If(clr_cnt, + cnt.eq(0) + ).Elif(inc_cnt, + cnt.eq(cnt+1) + ) + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + fsm.act("IDLE", + self.sink.ack.eq(1), + clr_cnt.eq(1), + If(self.sink.stb & self.sink.sop, + self.sink.ack.eq(0), + NextState("INSERT"), + ) + ) + fsm.act("INSERT", + self.source.stb.eq(1), + self.source.sop.eq(cnt==0), + chooser(preamble, cnt, self.source.d), + If(cnt == cnt_max, + If(self.source.ack, NextState("COPY")) + ).Else( + inc_cnt.eq(self.source.ack) + ) + ) + fsm.act("COPY", + Record.connect(self.sink, self.source), + self.source.sop.eq(0), + + If(self.sink.stb & self.sink.eop & self.source.ack, + NextState("IDLE"), + ) + ) + +class PreambleChecker(Module): + def __init__(self, d_w): + self.sink = Sink(eth_description(d_w)) + self.source = Source(eth_description(d_w)) + + ### + + preamble = Signal(64, reset=eth_preamble) + cnt_max = (64//d_w)-1 + cnt = Signal(max=cnt_max+1) + clr_cnt = Signal() + inc_cnt = Signal() + + self.sync += \ + If(clr_cnt, + cnt.eq(0) + ).Elif(inc_cnt, + cnt.eq(cnt+1) + ) + + discard = Signal() + clr_discard = Signal() + set_discard = Signal() + + self.sync += \ + If(clr_discard, + discard.eq(0) + ).Elif(set_discard, + discard.eq(1) + ) + + sop = Signal() + clr_sop = Signal() + set_sop = Signal() + self.sync += \ + If(clr_sop, + sop.eq(0) + ).Elif(set_sop, + sop.eq(1) + ) + + ref = Signal(d_w) + match = Signal() + self.comb += [ + chooser(preamble, cnt, ref), + match.eq(self.sink.d == ref) + ] + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + fsm.act("IDLE", + self.sink.ack.eq(1), + clr_cnt.eq(1), + clr_discard.eq(1), + If(self.sink.stb & self.sink.sop, + clr_cnt.eq(0), + inc_cnt.eq(1), + clr_discard.eq(0), + set_discard.eq(~match), + NextState("CHECK"), + ) + ) + fsm.act("CHECK", + self.sink.ack.eq(1), + If(self.sink.stb, + set_discard.eq(~match), + If(cnt == cnt_max, + If(discard | (~match), + NextState("IDLE") + ).Else( + set_sop.eq(1), + NextState("COPY") + ) + ).Else( + inc_cnt.eq(1) + ) + ) + ) + fsm.act("COPY", + Record.connect(self.sink, self.source), + self.source.sop.eq(sop), + clr_sop.eq(self.source.stb & self.source.ack), + + If(self.source.stb & self.source.eop & self.source.ack, + NextState("IDLE"), + ) + ) diff --git a/misoclib/ethmac/sram.py b/misoclib/ethmac/sram.py new file mode 100644 index 00000000..5160a8f6 --- /dev/null +++ b/misoclib/ethmac/sram.py @@ -0,0 +1,251 @@ +from migen.fhdl.std import * +from migen.genlib.fifo import SyncFIFO +from migen.genlib.fsm import FSM, NextState +from migen.genlib.misc import chooser +from migen.flow.actor import Sink, Source +from migen.bank.description import * +from migen.bank.eventmanager import * + +from misoclib.ethmac.std import * + +class SRAMWriter(Module, AutoCSR): + def __init__(self, depth, nslots=2): + self.sink = sink = Sink(eth_description(32)) + self.crc_error = Signal() + + slotbits = max(log2_int(nslots), 1) + lengthbits = log2_int(depth*4) # length in bytes + + self._slot = CSRStatus(slotbits) + self._length = CSRStatus(lengthbits) + + self.submodules.ev = EventManager() + self.ev.available = EventSourceLevel() + self.ev.finalize() + + ### + + # packet dropped if no slot available + sink.ack.reset = 1 + + # length computation + cnt = Signal(lengthbits) + clr_cnt = Signal() + inc_cnt = Signal() + inc_val = Signal(3) + self.comb += \ + If(sink.last_be[3], + inc_val.eq(1) + ).Elif(sink.last_be[2], + inc_val.eq(2) + ).Elif(sink.last_be[1], + inc_val.eq(3) + ).Else( + inc_val.eq(4) + ) + self.sync += \ + If(clr_cnt, + cnt.eq(0) + ).Elif(inc_cnt, + cnt.eq(cnt+inc_val) + ) + + # slot computation + slot = Signal(slotbits) + inc_slot = Signal() + self.sync += \ + If(inc_slot, + If(slot == nslots-1, + slot.eq(0), + ).Else( + slot.eq(slot+1) + ) + ) + ongoing = Signal() + discard = Signal() + + # status fifo + fifo = SyncFIFO([("slot", slotbits), ("length", lengthbits)], nslots) + self.submodules += fifo + + # fsm + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + fsm.act("IDLE", + inc_cnt.eq(sink.stb), + If(sink.stb & sink.sop, + ongoing.eq(1), + If(fifo.writable, + NextState("WRITE") + ) + ) + ) + fsm.act("WRITE", + inc_cnt.eq(sink.stb), + ongoing.eq(1), + If(sink.stb & sink.eop, + If((sink.error & sink.last_be) != 0, + NextState("DISCARD") + ).Else( + NextState("TERMINATE") + ) + ) + ) + fsm.act("DISCARD", + clr_cnt.eq(1), + NextState("IDLE") + ) + fsm.act("TERMINATE", + clr_cnt.eq(1), + inc_slot.eq(1), + fifo.we.eq(1), + fifo.din.slot.eq(slot), + fifo.din.length.eq(cnt), + NextState("IDLE") + ) + + self.comb += [ + fifo.re.eq(self.ev.available.clear), + self.ev.available.trigger.eq(fifo.readable), + self._slot.status.eq(fifo.dout.slot), + self._length.status.eq(fifo.dout.length), + ] + + # memory + mems = [None]*nslots + ports = [None]*nslots + for n in range(nslots): + mems[n] = Memory(32, depth) + ports[n] = mems[n].get_port(write_capable=True) + self.specials += ports[n] + self.mems = mems + + cases = {} + for n, port in enumerate(ports): + cases[n] = [ + ports[n].adr.eq(cnt[2:]), + ports[n].dat_w.eq(sink.d), + If(sink.stb & ongoing, + ports[n].we.eq(0xf) + ) + ] + self.comb += Case(slot, cases) + + +class SRAMReader(Module, AutoCSR): + def __init__(self, depth, nslots=2): + self.source = source = Source(eth_description(32)) + + slotbits = max(log2_int(nslots), 1) + lengthbits = log2_int(depth*4) # length in bytes + self.lengthbits = lengthbits + + self._start = CSR() + self._ready = CSRStatus() + self._slot = CSRStorage(slotbits) + self._length = CSRStorage(lengthbits) + + self.submodules.ev = EventManager() + self.ev.done = EventSourcePulse() + self.ev.finalize() + + ### + + # command fifo + fifo = SyncFIFO([("slot", slotbits), ("length", lengthbits)], nslots) + self.submodules += fifo + self.comb += [ + fifo.we.eq(self._start.re), + fifo.din.slot.eq(self._slot.storage), + fifo.din.length.eq(self._length.storage), + self._ready.status.eq(fifo.writable) + ] + + # length computation + cnt = Signal(lengthbits) + clr_cnt = Signal() + inc_cnt = Signal() + + self.sync += \ + If(clr_cnt, + cnt.eq(0) + ).Elif(inc_cnt, + cnt.eq(cnt+4) + ) + + # fsm + first = Signal() + last = Signal() + last_d = Signal() + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + fsm.act("IDLE", + clr_cnt.eq(1), + If(fifo.readable, + NextState("CHECK") + ) + ) + fsm.act("CHECK", + If(~last_d, + NextState("SEND"), + ).Else( + NextState("END"), + ) + ) + length_lsb = fifo.dout.length[0:2] + fsm.act("SEND", + source.stb.eq(1), + source.sop.eq(first), + source.eop.eq(last), + If(last, + If(length_lsb == 3, + source.last_be.eq(0b0010) + ).Elif(length_lsb == 2, + source.last_be.eq(0b0100) + ).Elif(length_lsb == 1, + source.last_be.eq(0b1000) + ).Else( + source.last_be.eq(0b0001) + ) + ), + If(source.ack, + inc_cnt.eq(~last), + NextState("CHECK") + ) + ) + fsm.act("END", + fifo.re.eq(1), + self.ev.done.trigger.eq(1), + NextState("IDLE") + ) + + # first/last computation + self.sync += [ + If(fsm.ongoing("IDLE"), + first.eq(1) + ).Elif(source.stb & source.ack, + first.eq(0) + ) + ] + self.comb += last.eq(cnt+4 >= fifo.dout.length) + self.sync += last_d.eq(last) + + # memory + rd_slot = fifo.dout.slot + + mems = [None]*nslots + ports = [None]*nslots + for n in range(nslots): + mems[n] = Memory(32, depth) + ports[n] = mems[n].get_port() + self.specials += ports[n] + self.mems = mems + + cases = {} + for n, port in enumerate(ports): + self.comb += ports[n].adr.eq(cnt[2:]) + cases[n] = [source.d.eq(port.dat_r)] + self.comb += Case(rd_slot, cases) diff --git a/misoclib/ethmac/std.py b/misoclib/ethmac/std.py new file mode 100644 index 00000000..5e5c1293 --- /dev/null +++ b/misoclib/ethmac/std.py @@ -0,0 +1,17 @@ +from migen.fhdl.std import * +from migen.flow.actor import EndpointDescription + +eth_mtu = 1532 +eth_preamble = 0xD555555555555555 +buffer_depth = 2**log2_int(eth_mtu, need_pow2=False) + +def eth_description(dw): + parameters = { + "packetized": True + } + layout = [ + ("d", dw), + ("last_be", dw//8), + ("error", dw//8) + ] + return EndpointDescription(layout, parameters) diff --git a/misoclib/ethmac/test/Makefile b/misoclib/ethmac/test/Makefile new file mode 100644 index 00000000..55d28e10 --- /dev/null +++ b/misoclib/ethmac/test/Makefile @@ -0,0 +1,13 @@ +MSCDIR = ../../../ +PYTHON = python3 + +CMD = PYTHONPATH=$(MSCDIR) $(PYTHON) + +crc_tb: + $(CMD) crc_tb.py + +preamble_tb: + $(CMD) preamble_tb.py + +ethmac_tb: + $(CMD) ethmac_tb.py diff --git a/misoclib/ethmac/test/__init__.py b/misoclib/ethmac/test/__init__.py new file mode 100644 index 00000000..f3ad9525 --- /dev/null +++ b/misoclib/ethmac/test/__init__.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) diff --git a/misoclib/ethmac/test/crc_tb.py b/misoclib/ethmac/test/crc_tb.py new file mode 100644 index 00000000..74fab284 --- /dev/null +++ b/misoclib/ethmac/test/crc_tb.py @@ -0,0 +1,61 @@ +from migen.fhdl.std import * +from migen.actorlib.crc import * + +from misoclib.ethmac.std import * + +from misoclib.ethmac.test import * + +frame_data = [ + 0x00, 0x0A, 0xE6, 0xF0, 0x05, 0xA3, 0x00, 0x12, + 0x34, 0x56, 0x78, 0x90, 0x08, 0x00, 0x45, 0x00, + 0x00, 0x30, 0xB3, 0xFE, 0x00, 0x00, 0x80, 0x11, + 0x72, 0xBA, 0x0A, 0x00, 0x00, 0x03, 0x0A, 0x00, + 0x00, 0x02, 0x04, 0x00, 0x04, 0x00, 0x00, 0x1C, + 0x89, 0x4D, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 +] + +frame_crc = [ + 0x7A, 0xD5, 0x6B, 0xB3 +] + +class TB(Module): + def __init__(self): + + sm = self.submodules + + # Streamer (DATA) --> CRC32Inserter --> Logger (expect DATA + CRC) + sm.inserter_streamer = PacketStreamer(frame_data) + sm.crc32_inserter = CRC32Inserter(eth_description(8)) + sm.inserter_logger = PacketLogger() + self.comb +=[ + self.inserter_streamer.source.connect(self.crc32_inserter.sink), + self.crc32_inserter.source.connect(self.inserter_logger.sink), + ] + + # Streamer (DATA + CRC) --> CRC32Checher --> Logger (except DATA + CRC + check) + sm.checker_streamer = PacketStreamer(frame_data+frame_crc) + sm.crc32_checker = CRC32Checker(eth_description(8)) + sm.checker_logger = PacketLogger() + self.comb +=[ + self.checker_streamer.source.connect(self.crc32_checker.sink), + self.crc32_checker.source.connect(self.checker_logger.sink), + ] + + def gen_simulation(self, selfp): + for i in range(500): + yield + inserter_reference = frame_data + frame_crc + inserter_generated = self.inserter_logger.data + + checker_reference = frame_data + checker_generated = self.checker_logger.data + + print_results("inserter", inserter_reference, inserter_generated) + print_results("checker", checker_reference, checker_generated) + + +if __name__ == "__main__": + from migen.sim.generic import run_simulation + run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True) diff --git a/misoclib/ethmac/test/ethmac_tb.py b/misoclib/ethmac/test/ethmac_tb.py new file mode 100644 index 00000000..7a02f35c --- /dev/null +++ b/misoclib/ethmac/test/ethmac_tb.py @@ -0,0 +1,134 @@ +from migen.fhdl.std import * +from migen.bus import wishbone +from migen.bus.transactions import * +from migen.sim.generic import run_simulation + +from misoclib.ethmac import EthMAC +from misoclib.ethmac.phys import loopback + +class WishboneMaster(): + def __init__(self, obj): + self.obj = obj + self.dat = 0 + + def write(self, adr, dat): + self.obj.cyc = 1 + self.obj.stb = 1 + self.obj.adr = adr + self.obj.we = 1 + self.obj.sel = 0xF + self.obj.dat_w = dat + while self.obj.ack == 0: + yield + self.obj.cyc = 0 + self.obj.stb = 0 + yield + + def read(self, adr): + self.obj.cyc = 1 + self.obj.stb = 1 + self.obj.adr = adr + self.obj.we = 0 + self.obj.sel = 0xF + self.obj.dat_w = 0 + while self.obj.ack == 0: + yield + self.dat = self.obj.dat_r + self.obj.cyc = 0 + self.obj.stb = 0 + yield + +class SRAMReaderDriver(): + def __init__(self, obj): + self.obj = obj + + def start(self, slot, length): + self.obj._slot.storage = slot + self.obj._length.storage = length + self.obj._start.re = 1 + yield + self.obj._start.re = 0 + yield + + def wait_done(self): + while self.obj.ev.done.pending == 0: + yield + def clear_done(self): + self.obj.ev.done.clear = 1 + yield + self.obj.ev.done.clear = 0 + yield + +class TB(Module): + def __init__(self): + self.submodules.ethphy = loopback.LoopbackPHY() + self.submodules.ethmac = EthMAC(phy=self.ethphy, with_hw_preamble_crc=True) + + # use sys_clk for each clock_domain + self.clock_domains.cd_eth_rx = ClockDomain() + self.clock_domains.cd_eth_tx = ClockDomain() + self.comb += [ + self.cd_eth_rx.clk.eq(ClockSignal()), + self.cd_eth_rx.rst.eq(ResetSignal()), + self.cd_eth_tx.clk.eq(ClockSignal()), + self.cd_eth_tx.rst.eq(ResetSignal()), + ] + + def gen_simulation(self, selfp): + selfp.cd_eth_rx.rst = 1 + selfp.cd_eth_tx.rst = 1 + yield + selfp.cd_eth_rx.rst = 0 + selfp.cd_eth_tx.rst = 0 + + wishbone_master = WishboneMaster(selfp.ethmac.bus) + sram_reader_driver = SRAMReaderDriver(selfp.ethmac.sram_reader) + + sram_writer_slots_offset = [0x000, 0x200] + sram_reader_slots_offset = [0x400, 0x600] + + length = 1500-2 + + payload = [i%0xFF for i in range(length)] + [0, 0, 0, 0] + + errors = 0 + + for slot in range(2): + # fill tx memory + for i in range(length//4+1): + dat = 0 + dat |= payload[4*i+0] << 24 + dat |= payload[4*i+1] << 16 + dat |= payload[4*i+2] << 8 + dat |= payload[4*i+3] << 0 + yield from wishbone_master.write(sram_reader_slots_offset[slot]+i, dat) + + # send tx data & wait + yield from sram_reader_driver.start(slot, length) + yield from sram_reader_driver.wait_done() + yield from sram_reader_driver.clear_done() + + # get rx data (loopback on PHY Model) + rx_dat = [] + for i in range(length//4+1): + yield from wishbone_master.read(sram_writer_slots_offset[slot]+i) + dat = wishbone_master.dat + rx_dat.append((dat >> 24) & 0xFF) + rx_dat.append((dat >> 16) & 0xFF) + rx_dat.append((dat >> 8) & 0xFF) + rx_dat.append((dat >> 0) & 0xFF) + + # check rx data + for i in range(length): + #print("%02x / %02x" %(rx_dat[i], payload[i])) + if rx_dat[i] != payload[i]: + errors += 1 + + for i in range(200): + yield + #print(selfp.ethmac.sram_reader._length.storage) + + print("Errors : %d" %errors) + +if __name__ == "__main__": + run_simulation(TB(), ncycles=16000, vcd_name="my.vcd", keep_files=True) diff --git a/misoclib/ethmac/test/preamble_tb.py b/misoclib/ethmac/test/preamble_tb.py new file mode 100644 index 00000000..8fca916d --- /dev/null +++ b/misoclib/ethmac/test/preamble_tb.py @@ -0,0 +1,61 @@ +from migen.fhdl.std import * + +from misoclib.ethmac.std import * +from misoclib.ethmac.preamble import * + +from misoclib.ethmac.test import * + +frame_preamble = [ + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5 +] + +frame_data = [ + 0x00, 0x0A, 0xE6, 0xF0, 0x05, 0xA3, 0x00, 0x12, + 0x34, 0x56, 0x78, 0x90, 0x08, 0x00, 0x45, 0x00, + 0x00, 0x30, 0xB3, 0xFE, 0x00, 0x00, 0x80, 0x11, + 0x72, 0xBA, 0x0A, 0x00, 0x00, 0x03, 0x0A, 0x00, + 0x00, 0x02, 0x04, 0x00, 0x04, 0x00, 0x00, 0x1C, + 0x89, 0x4D, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 +] + +class TB(Module): + def __init__(self): + + sm = self.submodules + + # Streamer (DATA) --> PreambleInserter --> Logger (expect PREAMBLE + DATA) + sm.inserter_streamer = PacketStreamer(frame_data) + sm.preamble_inserter = PreambleInserter(8) + sm.inserter_logger = PacketLogger() + self.comb +=[ + self.inserter_streamer.source.connect(self.preamble_inserter.sink), + self.preamble_inserter.source.connect(self.inserter_logger.sink), + ] + + # Streamer (PREAMBLE + DATA) --> CRC32Checher --> Logger (except DATA + check) + sm.checker_streamer = PacketStreamer(frame_preamble + frame_data) + sm.preamble_checker = PreambleChecker(8) + sm.checker_logger = PacketLogger() + self.comb +=[ + self.checker_streamer.source.connect(self.preamble_checker.sink), + self.preamble_checker.source.connect(self.checker_logger.sink), + ] + + + def gen_simulation(self, selfp): + for i in range(500): + yield + inserter_reference = frame_preamble + frame_data + inserter_generated = self.inserter_logger.data + + checker_reference = frame_data + checker_generated = self.checker_logger.data + + print_results("inserter", inserter_reference, inserter_generated) + print_results("checker", checker_reference, checker_generated) + +if __name__ == "__main__": + from migen.sim.generic import run_simulation + run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True) diff --git a/misoclib/minimac3/__init__.py b/misoclib/minimac3/__init__.py deleted file mode 100644 index ab6753a8..00000000 --- a/misoclib/minimac3/__init__.py +++ /dev/null @@ -1,81 +0,0 @@ -from migen.fhdl.std import * -from migen.bank.description import * -from migen.bank.eventmanager import * -from migen.bus import wishbone - -_count_width = 11 - -class MiniMAC(Module, AutoCSR): - def __init__(self, pads): - # CPU interface - self._phy_reset = CSRStorage(reset=1) - self._rx_count_0 = CSRStatus(_count_width) - self._rx_count_1 = CSRStatus(_count_width) - self._tx_count = CSRStorage(_count_width, write_from_dev=True) - self._tx_start = CSR() - - self.submodules.ev = EventManager() - self.ev.rx0 = EventSourcePulse() - self.ev.rx1 = EventSourcePulse() - self.ev.tx = EventSourcePulse() - self.ev.finalize() - - self.membus = wishbone.Interface() - - ### - - init = Signal(reset=1) - self.sync += init.eq(0) - rx_ready_0 = Signal() - rx_ready_1 = Signal() - rx_pending_0 = self.ev.rx0.pending - rx_pending_1 = self.ev.rx1.pending - rx_pending_0_r = Signal() - rx_pending_1_r = Signal() - self.comb += [ - pads.rst_n.eq(~self._phy_reset.storage), - - rx_ready_0.eq(init | (rx_pending_0_r & ~rx_pending_0)), - rx_ready_1.eq(init | (rx_pending_1_r & ~rx_pending_1)), - - self._tx_count.dat_w.eq(0), - self._tx_count.we.eq(self.ev.tx.trigger) - ] - self.sync += [ - rx_pending_0_r.eq(rx_pending_0), - rx_pending_1_r.eq(rx_pending_1) - ] - self.specials += Instance("minimac3", - Instance.Input("sys_clk", ClockSignal()), - Instance.Input("sys_rst", ResetSignal()), - - Instance.Output("rx_done_0", self.ev.rx0.trigger), - Instance.Output("rx_count_0", self._rx_count_0.status), - Instance.Output("rx_done_1", self.ev.rx1.trigger), - Instance.Output("rx_count_1", self._rx_count_1.status), - Instance.Input("rx_ready_0", rx_ready_0), - Instance.Input("rx_ready_1", rx_ready_1), - - Instance.Input("tx_start", self._tx_start.re), - Instance.Input("tx_count", self._tx_count.storage), - Instance.Output("tx_done", self.ev.tx.trigger), - - Instance.Input("wb_adr_i", self.membus.adr), - Instance.Input("wb_dat_i", self.membus.dat_w), - Instance.Input("wb_sel_i", self.membus.sel), - Instance.Input("wb_stb_i", self.membus.stb), - Instance.Input("wb_cyc_i", self.membus.cyc), - Instance.Input("wb_we_i", self.membus.we), - Instance.Output("wb_dat_o", self.membus.dat_r), - Instance.Output("wb_ack_o", self.membus.ack), - - Instance.Input("phy_tx_clk", ClockSignal("eth_tx")), - Instance.Output("phy_tx_data", pads.tx_data), - Instance.Output("phy_tx_en", pads.tx_en), - Instance.Output("phy_tx_er", pads.tx_er), - Instance.Input("phy_rx_clk", ClockSignal("eth_rx")), - Instance.Input("phy_rx_data", pads.rx_data), - Instance.Input("phy_dv", pads.dv), - Instance.Input("phy_rx_er", pads.rx_er), - Instance.Input("phy_col", pads.col), - Instance.Input("phy_crs", pads.crs)) diff --git a/misoclib/mxcrg/__init__.py b/misoclib/mxcrg/__init__.py index a4c83887..986e255b 100644 --- a/misoclib/mxcrg/__init__.py +++ b/misoclib/mxcrg/__init__.py @@ -8,8 +8,6 @@ class MXCRG(Module): self.clock_domains.cd_sdram_half = ClockDomain() self.clock_domains.cd_sdram_full_wr = ClockDomain() self.clock_domains.cd_sdram_full_rd = ClockDomain() - self.clock_domains.cd_eth_rx = ClockDomain() - self.clock_domains.cd_eth_tx = ClockDomain() self.clock_domains.cd_base50 = ClockDomain(reset_less=True) self.clk4x_wr_strb = Signal() @@ -28,21 +26,15 @@ class MXCRG(Module): Instance.Input("clk50_pad", pads.clk50), Instance.Input("trigger_reset", pads.trigger_reset), - Instance.Input("eth_rx_clk_pad", pads.eth_rx_clk), - Instance.Input("eth_tx_clk_pad", pads.eth_tx_clk), - Instance.Output("sys_clk", self.cd_sys.clk), Instance.Output("sys_rst", self.cd_sys.rst), Instance.Output("clk2x_270", self.cd_sdram_half.clk), Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk), Instance.Output("clk4x_rd", self.cd_sdram_full_rd.clk), - Instance.Output("eth_rx_clk", self.cd_eth_rx.clk), - Instance.Output("eth_tx_clk", self.cd_eth_tx.clk), Instance.Output("base50_clk", self.cd_base50.clk), Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb), Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb), Instance.Output("norflash_rst_n", pads.norflash_rst_n), Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p), - Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n), - Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk)) + Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n)) diff --git a/software/bios/boot.c b/software/bios/boot.c index 80cefdb7..1c5c14a8 100644 --- a/software/bios/boot.c +++ b/software/bios/boot.c @@ -176,7 +176,7 @@ void serialboot(void) } } -#ifdef MINIMAC_BASE +#ifdef ETHMAC_BASE #define LOCALIP1 192 #define LOCALIP2 168 @@ -258,7 +258,7 @@ void flashboot(void) printf("Error: Invalid flash boot image length 0x%08x\n", length); return; } - + printf("Loading %d bytes from flash...\n", length); memcpy((void *)SDRAM_BASE, flashbase, length); got_crc = crc32((unsigned char *)SDRAM_BASE, length); diff --git a/software/bios/main.c b/software/bios/main.c index 29b141ce..32f77a43 100644 --- a/software/bios/main.c +++ b/software/bios/main.c @@ -319,7 +319,7 @@ static void help(void) puts("rcsr - read processor CSR"); puts("wcsr - write processor CSR"); #endif -#ifdef MINIMAC_BASE +#ifdef ETHMAC_BASE puts("netboot - boot via TFTP"); #endif puts("serialboot - boot via SFL"); @@ -361,10 +361,10 @@ static void do_command(char *c) else if(strcmp(token, "flashboot") == 0) flashboot(); #endif else if(strcmp(token, "serialboot") == 0) serialboot(); -#ifdef MINIMAC_BASE +#ifdef ETHMAC_BASE else if(strcmp(token, "netboot") == 0) netboot(); #endif - + else if(strcmp(token, "revision") == 0) printf("%08x\n", MSC_GIT_ID); else if(strcmp(token, "help") == 0) help(); @@ -373,7 +373,7 @@ static void do_command(char *c) else if(strcmp(token, "rcsr") == 0) rcsr(get_token(&c)); else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c)); #endif - + #ifdef DFII_BASE else if(strcmp(token, "sdrrow") == 0) sdrrow(get_token(&c)); else if(strcmp(token, "sdrsw") == 0) sdrsw(); @@ -390,7 +390,7 @@ static void do_command(char *c) else if(strcmp(token, "memtest") == 0) memtest(); else if(strcmp(token, "sdrinit") == 0) sdrinit(); #endif - + else if(strcmp(token, "dfs") == 0) dfs(get_token(&c)); else if(strcmp(token, "") != 0) @@ -464,7 +464,7 @@ static int test_user_abort(void) printf("Automatic boot in 2 seconds...\n"); printf("Q/ESC: abort boot\n"); printf("F7: boot from serial\n"); -#ifdef MINIMAC_BASE +#ifdef ETHMAC_BASE printf("F8: boot from network\n"); #endif timer0_en_write(0); @@ -483,7 +483,7 @@ static int test_user_abort(void) serialboot(); return 0; } -#ifdef MINIMAC_BASE +#ifdef ETHMAC_BASE if(c == 0x07) { netboot(); return 0; @@ -502,7 +502,7 @@ static void boot_sequence(void) flashboot(); #endif serialboot(); -#ifdef MINIMAC_BASE +#ifdef ETHMAC_BASE netboot(); #endif printf("No boot medium found\n"); @@ -522,7 +522,7 @@ int main(int i, char **c) printf("Revision %08x built "__DATE__" "__TIME__"\n\n", MSC_GIT_ID); crcbios(); id_print(); -#ifdef MINIMAC_BASE +#ifdef ETHMAC_BASE ethreset(); #endif #ifdef DFII_BASE @@ -534,7 +534,7 @@ int main(int i, char **c) boot_sequence(); else printf("Memory initialization failed\n"); - + while(1) { putsnonl("\e[1mBIOS>\e[0m "); readstr(buffer, 64); diff --git a/software/include/hw/ethmac_mem.h b/software/include/hw/ethmac_mem.h new file mode 100644 index 00000000..c57e1751 --- /dev/null +++ b/software/include/hw/ethmac_mem.h @@ -0,0 +1,11 @@ +#ifndef __HW_ETHMAC_MEM_H +#define __HW_ETHMAC_MEM_H + +#include + +#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 diff --git a/software/include/hw/flags.h b/software/include/hw/flags.h index 01682e4c..911a1b68 100644 --- a/software/include/hw/flags.h +++ b/software/include/hw/flags.h @@ -16,9 +16,8 @@ #define DFII_COMMAND_WRDATA 0x10 #define DFII_COMMAND_RDDATA 0x20 -#define MINIMAC_EV_RX0 0x1 -#define MINIMAC_EV_RX1 0x2 -#define MINIMAC_EV_TX 0x4 +#define ETHMAC_EV_SRAM_WRITER 0x1 +#define ETHMAC_EV_SRAM_READER 0x1 #define CLKGEN_STATUS_BUSY 0x1 #define CLKGEN_STATUS_PROGDONE 0x2 diff --git a/software/include/hw/minimac_mem.h b/software/include/hw/minimac_mem.h deleted file mode 100644 index b93cc682..00000000 --- a/software/include/hw/minimac_mem.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __HW_MINIMAC_MEM_H -#define __HW_MINIMAC_MEM_H - -#include - -#define MINIMAC_RX0_BASE MINIMAC_MEM_BASE -#define MINIMAC_RX1_BASE (MINIMAC_MEM_BASE+0x0800) -#define MINIMAC_TX_BASE (MINIMAC_MEM_BASE+0x1000) - -#endif diff --git a/software/libnet/microudp.c b/software/libnet/microudp.c index bd5e2a08..a8faa45d 100644 --- a/software/libnet/microudp.c +++ b/software/libnet/microudp.c @@ -1,19 +1,25 @@ #include -#ifdef MINIMAC_BASE +#ifdef ETHMAC_BASE #include #include #include #include -#include +#include #include #define ETHERTYPE_ARP 0x0806 #define ETHERTYPE_IP 0x0800 +#ifdef CSR_ETHMAC_HW_PREAMBLE_CRC_ADDR +#define HW_PREAMBLE_CRC +#endif + struct ethernet_header { +#ifndef HW_PREAMBLE_CRC unsigned char preamble[8]; +#endif unsigned char destmac[6]; unsigned char srcmac[6]; unsigned short ethertype; @@ -23,9 +29,11 @@ static void fill_eth_header(struct ethernet_header *h, const unsigned char *dest { int i; +#ifndef HW_PREAMBLE_CRC for(i=0;i<7;i++) h->preamble[i] = 0x55; h->preamble[7] = 0xd5; +#endif for(i=0;i<6;i++) h->destmac[i] = destmac[i]; for(i=0;i<6;i++) @@ -35,6 +43,11 @@ static void fill_eth_header(struct ethernet_header *h, const unsigned char *dest #define ARP_HWTYPE_ETHERNET 0x0001 #define ARP_PROTO_IP 0x0800 +#ifndef HW_PREAMBLE_CRC +#define ARP_PACKET_LENGTH 68 +#else +#define ARP_PACKET_LENGTH 60 +#endif #define ARP_OPCODE_REQUEST 0x0001 #define ARP_OPCODE_REPLY 0x0002 @@ -97,27 +110,37 @@ typedef union { } ethernet_buffer; +static unsigned int rxslot; static unsigned int rxlen; static ethernet_buffer *rxbuffer; static ethernet_buffer *rxbuffer0; static ethernet_buffer *rxbuffer1; +static unsigned int txslot; static unsigned int txlen; static ethernet_buffer *txbuffer; +static ethernet_buffer *txbuffer0; +static ethernet_buffer *txbuffer1; static void send_packet(void) { +#ifndef HW_PREAMBLE_CRC unsigned int crc; - crc = crc32(&txbuffer->raw[8], txlen-8); txbuffer->raw[txlen ] = (crc & 0xff); txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8; txbuffer->raw[txlen+2] = (crc & 0xff0000) >> 16; txbuffer->raw[txlen+3] = (crc & 0xff000000) >> 24; txlen += 4; - minimac_tx_count_write(txlen); - minimac_tx_start_write(1); - while(!(minimac_ev_pending_read() & MINIMAC_EV_TX)); - minimac_ev_pending_write(MINIMAC_EV_TX); +#endif + ethmac_sram_reader_slot_write(txslot); + ethmac_sram_reader_length_write(txlen); + while(!(ethmac_sram_reader_ready_read())); + ethmac_sram_reader_start_write(1); + txslot = (txslot+1)%2; + if (txslot) + txbuffer = txbuffer1; + else + txbuffer = txbuffer0; } static unsigned char my_mac[6]; @@ -132,7 +155,7 @@ static void process_arp(void) const struct arp_frame *rx_arp = &rxbuffer->frame.contents.arp; struct arp_frame *tx_arp = &txbuffer->frame.contents.arp; - if(rxlen < 68) return; + if(rxlen < ARP_PACKET_LENGTH) return; if(rx_arp->hwtype != ARP_HWTYPE_ETHERNET) return; if(rx_arp->proto != ARP_PROTO_IP) return; if(rx_arp->hwsize != 6) return; @@ -148,12 +171,12 @@ static void process_arp(void) if(rx_arp->opcode == ARP_OPCODE_REQUEST) { if(rx_arp->target_ip == my_ip) { int i; - + fill_eth_header(&txbuffer->frame.eth_header, rx_arp->sender_mac, my_mac, ETHERTYPE_ARP); - txlen = 68; + txlen = ARP_PACKET_LENGTH; tx_arp->hwtype = ARP_HWTYPE_ETHERNET; tx_arp->proto = ARP_PROTO_IP; tx_arp->hwsize = 6; @@ -194,7 +217,7 @@ int microudp_arp_resolve(unsigned int ip) broadcast, my_mac, ETHERTYPE_ARP); - txlen = 68; + txlen = ARP_PACKET_LENGTH; arp->hwtype = ARP_HWTYPE_ETHERNET; arp->proto = ARP_PROTO_IP; arp->hwsize = 6; @@ -259,19 +282,19 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int { struct pseudo_header h; unsigned int r; - + if((cached_mac[0] == 0) && (cached_mac[1] == 0) && (cached_mac[2] == 0) && (cached_mac[3] == 0) && (cached_mac[4] == 0) && (cached_mac[5] == 0)) return 0; txlen = length + sizeof(struct ethernet_header) + sizeof(struct udp_frame); - if(txlen < 68) txlen = 68; - + if(txlen < ARP_PACKET_LENGTH) txlen = ARP_PACKET_LENGTH; + fill_eth_header(&txbuffer->frame.eth_header, cached_mac, my_mac, ETHERTYPE_IP); - + txbuffer->frame.contents.udp.ip.version = IP_IPV4; txbuffer->frame.contents.udp.ip.diff_services = 0; txbuffer->frame.contents.udp.ip.total_length = length + sizeof(struct udp_frame); @@ -299,7 +322,7 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int r = ip_checksum(r, &txbuffer->frame.contents.udp.udp, sizeof(struct udp_header)+length, 1); txbuffer->frame.contents.udp.udp.checksum = r; - + send_packet(); return 1; @@ -332,14 +355,18 @@ void microudp_set_callback(udp_callback callback) static void process_frame(void) { - int i; - unsigned int received_crc; - unsigned int computed_crc; - flush_cpu_dcache(); + +#ifndef HW_PREAMBLE_CRC + int i; for(i=0;i<7;i++) if(rxbuffer->frame.eth_header.preamble[i] != 0x55) return; if(rxbuffer->frame.eth_header.preamble[7] != 0xd5) return; +#endif + +#ifndef HW_PREAMBLE_CRC + unsigned int received_crc; + unsigned int computed_crc; received_crc = ((unsigned int)rxbuffer->raw[rxlen-1] << 24) |((unsigned int)rxbuffer->raw[rxlen-2] << 16) |((unsigned int)rxbuffer->raw[rxlen-3] << 8) @@ -348,6 +375,8 @@ static void process_frame(void) if(received_crc != computed_crc) return; rxlen -= 4; /* strip CRC here to be consistent with TX */ +#endif + if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_ARP) process_arp(); else if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_IP) process_ip(); } @@ -355,12 +384,19 @@ static void process_frame(void) void microudp_start(const unsigned char *macaddr, unsigned int ip) { int i; + ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER); + ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); + + rxbuffer0 = (ethernet_buffer *)ETHMAC_RX0_BASE; + rxbuffer1 = (ethernet_buffer *)ETHMAC_RX1_BASE; + txbuffer0 = (ethernet_buffer *)ETHMAC_TX0_BASE; + txbuffer1 = (ethernet_buffer *)ETHMAC_TX1_BASE; - minimac_ev_pending_write(MINIMAC_EV_RX0 | MINIMAC_EV_RX1 | MINIMAC_EV_TX); - - rxbuffer0 = (ethernet_buffer *)MINIMAC_RX0_BASE; - rxbuffer1 = (ethernet_buffer *)MINIMAC_RX1_BASE; - txbuffer = (ethernet_buffer *)MINIMAC_TX_BASE; + rxslot = 0; + txslot = 0; + + rxbuffer = rxbuffer0; + txbuffer = txbuffer0; for(i=0;i<6;i++) my_mac[i] = macaddr[i]; @@ -375,17 +411,15 @@ void microudp_start(const unsigned char *macaddr, unsigned int ip) void microudp_service(void) { - if(minimac_ev_pending_read() & MINIMAC_EV_RX0) { - rxlen = minimac_rx_count_0_read(); - rxbuffer = rxbuffer0; - process_frame(); - minimac_ev_pending_write(MINIMAC_EV_RX0); - } - if(minimac_ev_pending_read() & MINIMAC_EV_RX1) { - rxlen = minimac_rx_count_1_read(); - rxbuffer = rxbuffer1; + if(ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER) { + rxslot = ethmac_sram_writer_slot_read(); + rxlen = ethmac_sram_writer_length_read(); + if (rxslot) + rxbuffer = rxbuffer1; + else + rxbuffer = rxbuffer0; process_frame(); - minimac_ev_pending_write(MINIMAC_EV_RX1); + ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); } } @@ -401,12 +435,12 @@ static void busy_wait(unsigned int ds) void ethreset(void) { - minimac_phy_reset_write(0); + ethphy_crg_reset_write(0); busy_wait(2); /* that pesky ethernet PHY needs two resets at times... */ - minimac_phy_reset_write(1); + ethphy_crg_reset_write(1); busy_wait(2); - minimac_phy_reset_write(0); + ethphy_crg_reset_write(0); busy_wait(2); } diff --git a/software/libnet/tftp.c b/software/libnet/tftp.c index 2bf0eac6..45796844 100644 --- a/software/libnet/tftp.c +++ b/software/libnet/tftp.c @@ -70,7 +70,7 @@ static void rx_callback(uint32_t src_ip, uint16_t src_port, uint16_t block; int i; int offset; - + if(length < 4) return; if(dst_port != PORT_IN) return; opcode = data[0] << 8 | data[1]; @@ -89,7 +89,8 @@ static void rx_callback(uint32_t src_ip, uint16_t src_port, total_length += length; if(length < BLOCK_SIZE) transfer_finished = 1; - + + packet_data = microudp_get_tx_buffer(); length = format_ack(packet_data, block); microudp_send(PORT_IN, src_port, length); } @@ -105,19 +106,19 @@ int tftp_get(uint32_t ip, const char *filename, void *buffer) int tries; int i; int length_before; - + if(!microudp_arp_resolve(ip)) return -1; microudp_set_callback(rx_callback); - packet_data = microudp_get_tx_buffer(); dst_buffer = buffer; total_length = 0; transfer_finished = 0; tries = 5; while(1) { + packet_data = microudp_get_tx_buffer(); len = format_request(packet_data, TFTP_RRQ, filename); microudp_send(PORT_IN, PORT_OUT, len); for(i=0;i<2000000;i++) { @@ -156,7 +157,7 @@ int tftp_put(uint32_t ip, const char *filename, const void *buffer, int size) int tries; int i; int block = 0, sent = 0; - + if(!microudp_arp_resolve(ip)) return -1; @@ -168,6 +169,7 @@ int tftp_put(uint32_t ip, const char *filename, const void *buffer, int size) transfer_finished = 0; tries = 5; while(1) { + packet_data = microudp_get_tx_buffer(); len = format_request(packet_data, TFTP_WRQ, filename); microudp_send(PORT_IN, PORT_OUT, len); for(i=0;i<2000000;i++) { @@ -189,6 +191,7 @@ send_data: send = sent+BLOCK_SIZE > size ? size-sent : BLOCK_SIZE; tries = 5; while(1) { + packet_data = microudp_get_tx_buffer(); len = format_data(packet_data, block, buffer, send); microudp_send(PORT_IN, data_port, len); for(i=0;i<12000000;i++) { diff --git a/targets/kc705.py b/targets/kc705.py index 8c78ad76..1aab9ef4 100644 --- a/targets/kc705.py +++ b/targets/kc705.py @@ -1,9 +1,10 @@ from migen.fhdl.std import * from migen.genlib.resetsync import AsyncResetSynchronizer -from misoclib import lasmicon, spiflash +from misoclib import lasmicon, spiflash, ethmac from misoclib.sdramphy import k7ddrphy from misoclib.gensoc import SDRAMSoC +from misoclib.ethmac.phys import gmii class _CRG(Module): def __init__(self, platform): @@ -104,4 +105,24 @@ class BaseSoC(SDRAMSoC): self.flash_boot_address = 0xb00000 self.register_rom(self.spiflash.bus) +class MiniSoC(BaseSoC): + csr_map = { + "ethphy": 10, + "ethmac": 11, + } + csr_map.update(BaseSoC.csr_map) + + interrupt_map = { + "ethmac": 2, + } + interrupt_map.update(BaseSoC.interrupt_map) + + def __init__(self, platform, **kwargs): + BaseSoC.__init__(self, platform, **kwargs) + + self.submodules.ethphy = gmii.GMIIPHY(platform.request("eth_clocks"), platform.request("eth")) + self.submodules.ethmac = ethmac.EthMAC(phy=self.ethphy, with_hw_preamble_crc=True) + self.add_wb_slave(lambda a: a[26:29] == 3, self.ethmac.bus) + self.add_cpu_memory_region("ethmac_mem", 0xb0000000, 0x2000) + default_subtarget = BaseSoC diff --git a/targets/mlabs_video.py b/targets/mlabs_video.py index 79ad4ae3..d2338015 100644 --- a/targets/mlabs_video.py +++ b/targets/mlabs_video.py @@ -4,9 +4,10 @@ from fractions import Fraction from migen.fhdl.std import * from mibuild.generic_platform import ConstraintError -from misoclib import lasmicon, mxcrg, norflash16, minimac3, framebuffer, gpio +from misoclib import lasmicon, mxcrg, norflash16, ethmac, framebuffer, gpio from misoclib.sdramphy import s6ddrphy from misoclib.gensoc import SDRAMSoC +from misoclib.ethmac.phys import mii class _MXClockPads: def __init__(self, platform): @@ -20,10 +21,6 @@ class _MXClockPads: ddram_clock = platform.request("ddram_clock") self.ddr_clk_p = ddram_clock.p self.ddr_clk_n = ddram_clock.n - eth_clocks = platform.request("eth_clocks") - self.eth_phy_clk = eth_clocks.phy - self.eth_rx_clk = eth_clocks.rx - self.eth_tx_clk = eth_clocks.tx class BaseSoC(SDRAMSoC): default_platform = "mixxeo" # also supports m1 @@ -75,12 +72,13 @@ PIN "mxcrg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE; class MiniSoC(BaseSoC): csr_map = { - "minimac": 10, + "ethphy": 10, + "ethmac": 11, } csr_map.update(BaseSoC.csr_map) interrupt_map = { - "minimac": 2, + "ethmac": 2, } interrupt_map.update(BaseSoC.interrupt_map) @@ -93,10 +91,10 @@ class MiniSoC(BaseSoC): self.submodules.buttons = gpio.GPIOIn(Cat(platform.request("user_btn", 0), platform.request("user_btn", 2))) self.submodules.leds = gpio.GPIOOut(Cat(platform.request("user_led", i) for i in range(2))) - self.submodules.minimac = minimac3.MiniMAC(platform.request("eth")) - self.add_wb_slave(lambda a: a[26:29] == 3, self.minimac.membus) - self.add_cpu_memory_region("minimac_mem", 0xb0000000, 0x1800) - platform.add_source_dir(os.path.join("verilog", "minimac3")) + self.submodules.ethphy = mii.MIIPHY(platform.request("eth_clocks"), platform.request("eth")) + self.submodules.ethmac = ethmac.EthMAC(phy=self.ethphy, with_hw_preamble_crc=False) + self.add_wb_slave(lambda a: a[26:29] == 3, self.ethmac.bus) + self.add_cpu_memory_region("ethmac_mem", 0xb0000000, 0x2000) def get_vga_dvi(platform): try: diff --git a/verilog/minimac3/minimac3.v b/verilog/minimac3/minimac3.v deleted file mode 100644 index a1e6bd8a..00000000 --- a/verilog/minimac3/minimac3.v +++ /dev/null @@ -1,138 +0,0 @@ -module minimac3( - input sys_clk, - input sys_rst, - - /* Control */ - input rx_ready_0, - output rx_done_0, - output [10:0] rx_count_0, - input rx_ready_1, - output rx_done_1, - output [10:0] rx_count_1, - - input tx_start, - output tx_done, - input [10:0] tx_count, - - /* WISHBONE to access RAM */ - input [29:0] wb_adr_i, - output [31:0] wb_dat_o, - input [31:0] wb_dat_i, - input [3:0] wb_sel_i, - input wb_stb_i, - input wb_cyc_i, - output wb_ack_o, - input wb_we_i, - - /* To PHY */ - input phy_tx_clk, - output [3:0] phy_tx_data, - output phy_tx_en, - output phy_tx_er, - input phy_rx_clk, - input [3:0] phy_rx_data, - input phy_dv, - input phy_rx_er, - input phy_col, - input phy_crs -); - -wire [1:0] phy_rx_ready; -wire [1:0] phy_rx_done; -wire [10:0] phy_rx_count_0; -wire [10:0] phy_rx_count_1; -wire phy_tx_start; -wire phy_tx_done; -wire [10:0] phy_tx_count; - -minimac3_sync sync( - .sys_clk(sys_clk), - .phy_rx_clk(phy_rx_clk), - .phy_tx_clk(phy_tx_clk), - - .sys_rx_ready({rx_ready_1, rx_ready_0}), - .sys_rx_done({rx_done_1, rx_done_0}), - .sys_rx_count_0(rx_count_0), - .sys_rx_count_1(rx_count_1), - .sys_tx_start(tx_start), - .sys_tx_done(tx_done), - .sys_tx_count(tx_count), - - .phy_rx_ready(phy_rx_ready), - .phy_rx_done(phy_rx_done), - .phy_rx_count_0(phy_rx_count_0), - .phy_rx_count_1(phy_rx_count_1), - .phy_tx_start(phy_tx_start), - .phy_tx_done(phy_tx_done), - .phy_tx_count(phy_tx_count) -); - -wire [7:0] rxb0_dat; -wire [10:0] rxb0_adr; -wire rxb0_we; -wire [7:0] rxb1_dat; -wire [10:0] rxb1_adr; -wire rxb1_we; -wire [7:0] txb_dat; -wire [10:0] txb_adr; -minimac3_memory memory( - .sys_clk(sys_clk), - .sys_rst(sys_rst), - .phy_rx_clk(phy_rx_clk), - .phy_tx_clk(phy_tx_clk), - - .wb_adr_i(wb_adr_i), - .wb_dat_o(wb_dat_o), - .wb_dat_i(wb_dat_i), - .wb_sel_i(wb_sel_i), - .wb_stb_i(wb_stb_i), - .wb_cyc_i(wb_cyc_i), - .wb_ack_o(wb_ack_o), - .wb_we_i(wb_we_i), - - .rxb0_dat(rxb0_dat), - .rxb0_adr(rxb0_adr), - .rxb0_we(rxb0_we), - .rxb1_dat(rxb1_dat), - .rxb1_adr(rxb1_adr), - .rxb1_we(rxb1_we), - - .txb_dat(txb_dat), - .txb_adr(txb_adr) -); - -minimac3_tx tx( - .phy_tx_clk(phy_tx_clk), - - .tx_start(phy_tx_start), - .tx_done(phy_tx_done), - .tx_count(phy_tx_count), - .txb_dat(txb_dat), - .txb_adr(txb_adr), - - .phy_tx_en(phy_tx_en), - .phy_tx_data(phy_tx_data) -); -assign phy_tx_er = 1'b0; - -minimac3_rx rx( - .phy_rx_clk(phy_rx_clk), - - .rx_ready(phy_rx_ready), - .rx_done(phy_rx_done), - .rx_count_0(phy_rx_count_0), - .rx_count_1(phy_rx_count_1), - - .rxb0_dat(rxb0_dat), - .rxb0_adr(rxb0_adr), - .rxb0_we(rxb0_we), - .rxb1_dat(rxb1_dat), - .rxb1_adr(rxb1_adr), - .rxb1_we(rxb1_we), - - .phy_dv(phy_dv), - .phy_rx_data(phy_rx_data), - .phy_rx_er(phy_rx_er) -); - -endmodule diff --git a/verilog/minimac3/minimac3_memory.v b/verilog/minimac3/minimac3_memory.v deleted file mode 100644 index f527bb39..00000000 --- a/verilog/minimac3/minimac3_memory.v +++ /dev/null @@ -1,152 +0,0 @@ -/* TODO: use behavioral BRAM models (Xst can extract byte WE) */ - -module minimac3_memory( - input sys_clk, - input sys_rst, - input phy_rx_clk, - input phy_tx_clk, - - input [29:0] wb_adr_i, - output [31:0] wb_dat_o, - input [31:0] wb_dat_i, - input [3:0] wb_sel_i, - input wb_stb_i, - input wb_cyc_i, - output reg wb_ack_o, - input wb_we_i, - - input [7:0] rxb0_dat, - input [10:0] rxb0_adr, - input rxb0_we, - input [7:0] rxb1_dat, - input [10:0] rxb1_adr, - input rxb1_we, - - output [7:0] txb_dat, - input [10:0] txb_adr - -); - -wire wb_en = wb_cyc_i & wb_stb_i; -wire [1:0] wb_buf = wb_adr_i[10:9]; -wire [31:0] wb_dat_i_le = {wb_dat_i[7:0], wb_dat_i[15:8], wb_dat_i[23:16], wb_dat_i[31:24]}; -wire [3:0] wb_sel_i_le = {wb_sel_i[0], wb_sel_i[1], wb_sel_i[2], wb_sel_i[3]}; - -wire [31:0] rxb0_wbdat; -RAMB16BWER #( - .DATA_WIDTH_A(36), - .DATA_WIDTH_B(9), - .DOA_REG(0), - .DOB_REG(0), - .EN_RSTRAM_A("FALSE"), - .EN_RSTRAM_B("FALSE"), - .SIM_DEVICE("SPARTAN6"), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST") -) rxb0 ( - .DIA(wb_dat_i_le), - .DIPA(4'd0), - .DOA(rxb0_wbdat), - .ADDRA({wb_adr_i[8:0], 5'd0}), - .WEA({4{wb_en & wb_we_i & (wb_buf == 2'b00)}} & wb_sel_i_le), - .ENA(1'b1), - .RSTA(1'b0), - .CLKA(sys_clk), - - .DIB(rxb0_dat), - .DIPB(1'd0), - .DOB(), - .ADDRB({rxb0_adr, 3'd0}), - .WEB({4{rxb0_we}}), - .ENB(1'b1), - .RSTB(1'b0), - .CLKB(phy_rx_clk) -); - -wire [31:0] rxb1_wbdat; -RAMB16BWER #( - .DATA_WIDTH_A(36), - .DATA_WIDTH_B(9), - .DOA_REG(0), - .DOB_REG(0), - .EN_RSTRAM_A("FALSE"), - .EN_RSTRAM_B("FALSE"), - .SIM_DEVICE("SPARTAN6"), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST") -) rxb1 ( - .DIA(wb_dat_i_le), - .DIPA(4'd0), - .DOA(rxb1_wbdat), - .ADDRA({wb_adr_i[8:0], 5'd0}), - .WEA({4{wb_en & wb_we_i & (wb_buf == 2'b01)}} & wb_sel_i_le), - .ENA(1'b1), - .RSTA(1'b0), - .CLKA(sys_clk), - - .DIB(rxb1_dat), - .DIPB(1'd0), - .DOB(), - .ADDRB({rxb1_adr, 3'd0}), - .WEB({4{rxb1_we}}), - .ENB(1'b1), - .RSTB(1'b0), - .CLKB(phy_rx_clk) -); - -wire [31:0] txb_wbdat; -RAMB16BWER #( - .DATA_WIDTH_A(36), - .DATA_WIDTH_B(9), - .DOA_REG(0), - .DOB_REG(0), - .EN_RSTRAM_A("FALSE"), - .EN_RSTRAM_B("FALSE"), - .SIM_DEVICE("SPARTAN6"), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST") -) txb ( - .DIA(wb_dat_i_le), - .DIPA(4'd0), - .DOA(txb_wbdat), - .ADDRA({wb_adr_i[8:0], 5'd0}), - .WEA({4{wb_en & wb_we_i & (wb_buf == 2'b10)}} & wb_sel_i_le), - .ENA(1'b1), - .RSTA(1'b0), - .CLKA(sys_clk), - - .DIB(8'd0), - .DIPB(1'd0), - .DOB(txb_dat), - .ADDRB({txb_adr, 3'd0}), - .WEB(4'd0), - .ENB(1'b1), - .RSTB(1'b0), - .CLKB(phy_tx_clk) -); - -always @(posedge sys_clk) begin - if(sys_rst) - wb_ack_o <= 1'b0; - else begin - wb_ack_o <= 1'b0; - if(wb_en & ~wb_ack_o) - wb_ack_o <= 1'b1; - end -end - -reg [1:0] wb_buf_r; -always @(posedge sys_clk) - wb_buf_r <= wb_buf; - -reg [31:0] wb_dat_o_le; -always @(*) begin - case(wb_buf_r) - 2'b00: wb_dat_o_le = rxb0_wbdat; - 2'b01: wb_dat_o_le = rxb1_wbdat; - default: wb_dat_o_le = txb_wbdat; - endcase -end -assign wb_dat_o = {wb_dat_o_le[7:0], wb_dat_o_le[15:8], wb_dat_o_le[23:16], wb_dat_o_le[31:24]}; - -endmodule diff --git a/verilog/minimac3/minimac3_rx.v b/verilog/minimac3/minimac3_rx.v deleted file mode 100644 index 6007fa65..00000000 --- a/verilog/minimac3/minimac3_rx.v +++ /dev/null @@ -1,129 +0,0 @@ -module minimac3_rx( - input phy_rx_clk, - - input [1:0] rx_ready, - output [1:0] rx_done, - output reg [10:0] rx_count_0, - output reg [10:0] rx_count_1, - - output [7:0] rxb0_dat, - output [10:0] rxb0_adr, - output rxb0_we, - output [7:0] rxb1_dat, - output [10:0] rxb1_adr, - output rxb1_we, - - input phy_dv, - input [3:0] phy_rx_data, - input phy_rx_er -); - -reg [1:0] available_slots; -always @(posedge phy_rx_clk) - available_slots <= (available_slots & ~rx_done) | rx_ready; -initial available_slots <= 2'd0; - -reg [1:0] used_slot; -reg used_slot_update; -always @(posedge phy_rx_clk) begin - if(used_slot_update) begin - used_slot[0] <= available_slots[0]; - used_slot[1] <= available_slots[1] & ~available_slots[0]; - end -end - -reg rx_done_ctl; -assign rx_done = {2{rx_done_ctl}} & used_slot; - -reg rx_count_reset_ctl; -reg rx_count_inc_ctl; -wire [1:0] rx_count_reset = {2{rx_count_reset_ctl}} & used_slot; -wire [1:0] rx_count_inc = {2{rx_count_inc_ctl}} & used_slot; -always @(posedge phy_rx_clk) begin - if(rx_count_reset[0]) - rx_count_0 <= 11'd0; - else if(rx_count_inc[0]) - rx_count_0 <= rx_count_0 + 11'd1; - if(rx_count_reset[1]) - rx_count_1 <= 11'd0; - else if(rx_count_inc[1]) - rx_count_1 <= rx_count_1 + 11'd1; -end - -assign rxb0_adr = rx_count_0; -assign rxb1_adr = rx_count_1; -reg rxb_we_ctl; -assign rxb0_we = rxb_we_ctl & used_slot[0]; -assign rxb1_we = rxb_we_ctl & used_slot[1]; - -reg [3:0] lo; -reg [3:0] hi; -reg [1:0] load_nibble; -always @(posedge phy_rx_clk) begin - if(load_nibble[0]) - lo <= phy_rx_data; - if(load_nibble[1]) - hi <= phy_rx_data; -end -assign rxb0_dat = {hi, lo}; -assign rxb1_dat = {hi, lo}; - -reg [1:0] state; -reg [1:0] next_state; - -parameter IDLE = 2'd0; -parameter LOAD_LO = 2'd1; -parameter LOAD_HI = 2'd2; -parameter TERMINATE = 2'd3; - -initial state <= IDLE; -always @(posedge phy_rx_clk) - state <= next_state; - -always @(*) begin - used_slot_update = 1'b0; - rx_done_ctl = 1'b0; - rx_count_reset_ctl = 1'b0; - rx_count_inc_ctl = 1'b0; - rxb_we_ctl = 1'b0; - load_nibble = 2'b00; - - next_state = state; - case(state) - IDLE: begin - used_slot_update = 1'b1; - if(phy_dv) begin - rx_count_reset_ctl = 1'b1; - used_slot_update = 1'b0; - load_nibble = 2'b01; - next_state = LOAD_HI; - end - end - LOAD_LO: begin - rxb_we_ctl = 1'b1; - rx_count_inc_ctl = 1'b1; - if(phy_dv) begin - load_nibble = 2'b01; - next_state = LOAD_HI; - end else begin - rx_done_ctl = 1'b1; - next_state = TERMINATE; - end - end - LOAD_HI: begin - if(phy_dv) begin - load_nibble = 2'b10; - next_state = LOAD_LO; - end else begin - rx_done_ctl = 1'b1; - next_state = TERMINATE; - end - end - TERMINATE: begin - used_slot_update = 1'b1; - next_state = IDLE; - end - endcase -end - -endmodule diff --git a/verilog/minimac3/minimac3_sync.v b/verilog/minimac3/minimac3_sync.v deleted file mode 100644 index c169ce29..00000000 --- a/verilog/minimac3/minimac3_sync.v +++ /dev/null @@ -1,76 +0,0 @@ -module minimac3_sync( - input sys_clk, - input phy_rx_clk, - input phy_tx_clk, - - input [1:0] sys_rx_ready, - output [1:0] sys_rx_done, - output reg [10:0] sys_rx_count_0, - output reg [10:0] sys_rx_count_1, - - input sys_tx_start, - output sys_tx_done, - input [10:0] sys_tx_count, - - output [1:0] phy_rx_ready, - input [1:0] phy_rx_done, - input [10:0] phy_rx_count_0, - input [10:0] phy_rx_count_1, - - output phy_tx_start, - input phy_tx_done, - output reg [10:0] phy_tx_count -); - -psync rx_ready_0( - .clk1(sys_clk), - .i(sys_rx_ready[0]), - .clk2(phy_rx_clk), - .o(phy_rx_ready[0]) -); -psync rx_ready_1( - .clk1(sys_clk), - .i(sys_rx_ready[1]), - .clk2(phy_rx_clk), - .o(phy_rx_ready[1]) -); -psync rx_done_0( - .clk1(phy_rx_clk), - .i(phy_rx_done[0]), - .clk2(sys_clk), - .o(sys_rx_done[0]) -); -psync rx_done_1( - .clk1(phy_rx_clk), - .i(phy_rx_done[1]), - .clk2(sys_clk), - .o(sys_rx_done[1]) -); -reg [10:0] sys_rx_count_0_r; -reg [10:0] sys_rx_count_1_r; -always @(posedge sys_clk) begin - sys_rx_count_0_r <= phy_rx_count_0; - sys_rx_count_0 <= sys_rx_count_0_r; - sys_rx_count_1_r <= phy_rx_count_1; - sys_rx_count_1 <= sys_rx_count_1_r; -end - -psync tx_start( - .clk1(sys_clk), - .i(sys_tx_start), - .clk2(phy_tx_clk), - .o(phy_tx_start) -); -psync tx_done( - .clk1(phy_tx_clk), - .i(phy_tx_done), - .clk2(sys_clk), - .o(sys_tx_done) -); -reg [10:0] phy_tx_count_r; -always @(posedge phy_tx_clk) begin - phy_tx_count_r <= sys_tx_count; - phy_tx_count <= phy_tx_count_r; -end - -endmodule diff --git a/verilog/minimac3/minimac3_tx.v b/verilog/minimac3/minimac3_tx.v deleted file mode 100644 index caf901a1..00000000 --- a/verilog/minimac3/minimac3_tx.v +++ /dev/null @@ -1,83 +0,0 @@ -module minimac3_tx( - input phy_tx_clk, - - input tx_start, - output reg tx_done, - input [10:0] tx_count, - input [7:0] txb_dat, - output [10:0] txb_adr, - - output reg phy_tx_en, - output reg [3:0] phy_tx_data -); - -reg phy_tx_en_r; -reg phy_tx_data_sel; -wire [3:0] phy_tx_data_r = phy_tx_data_sel ? txb_dat[7:4] : txb_dat[3:0]; -always @(posedge phy_tx_clk) begin - phy_tx_en <= phy_tx_en_r; - phy_tx_data <= phy_tx_data_r; -end - -reg [10:0] byte_count; -reg byte_count_reset; -reg byte_count_inc; -always @(posedge phy_tx_clk) begin - if(byte_count_reset) - byte_count <= 11'd0; - else if(byte_count_inc) - byte_count <= byte_count + 11'd1; -end -assign txb_adr = byte_count; -wire byte_count_max = byte_count == tx_count; - -parameter IDLE = 2'd0; -parameter SEND_LO = 2'd1; -parameter SEND_HI = 2'd2; -parameter TERMINATE = 2'd3; - -reg [1:0] state; -reg [1:0] next_state; - -initial state <= IDLE; -always @(posedge phy_tx_clk) - state <= next_state; - -always @(*) begin - phy_tx_en_r = 1'b0; - phy_tx_data_sel = 1'b0; - byte_count_reset = 1'b0; - byte_count_inc = 1'b0; - tx_done = 1'b0; - - next_state = state; - - case(state) - IDLE: begin - byte_count_reset = 1'b1; - if(tx_start) - next_state = SEND_LO; - end - SEND_LO: begin - byte_count_inc = 1'b1; - phy_tx_en_r = 1'b1; - phy_tx_data_sel = 1'b0; - next_state = SEND_HI; - end - SEND_HI: begin - phy_tx_en_r = 1'b1; - phy_tx_data_sel = 1'b1; - if(byte_count_max) - next_state = TERMINATE; - else - next_state = SEND_LO; - end - TERMINATE: begin - byte_count_reset = 1'b1; - tx_done = 1'b1; - next_state = IDLE; - end - endcase -end - -endmodule diff --git a/verilog/minimac3/psync.v b/verilog/minimac3/psync.v deleted file mode 100644 index 26597bb7..00000000 --- a/verilog/minimac3/psync.v +++ /dev/null @@ -1,31 +0,0 @@ -module psync( - input clk1, - input i, - input clk2, - output o -); - -reg level; -always @(posedge clk1) - if(i) - level <= ~level; - -reg level1; -reg level2; -reg level3; -always @(posedge clk2) begin - level1 <= level; - level2 <= level1; - level3 <= level2; -end - -assign o = level2 ^ level3; - -initial begin - level <= 1'b0; - level1 <= 1'b0; - level2 <= 1'b0; - level3 <= 1'b0; -end - -endmodule diff --git a/verilog/mxcrg/mxcrg.v b/verilog/mxcrg/mxcrg.v index 63052eef..140c8483 100644 --- a/verilog/mxcrg/mxcrg.v +++ b/verilog/mxcrg/mxcrg.v @@ -6,13 +6,13 @@ module mxcrg #( ) ( input clk50_pad, input trigger_reset, - + output sys_clk, output reg sys_rst, - + /* Reset NOR flash */ output norflash_rst_n, - + /* DDR PHY clocks */ output clk2x_270, output clk4x_wr, @@ -23,14 +23,7 @@ module mxcrg #( /* DDR off-chip clocking */ output ddr_clk_pad_p, output ddr_clk_pad_n, - - /* Ethernet PHY clocks */ - output reg eth_phy_clk_pad, - input eth_rx_clk_pad, - input eth_tx_clk_pad, - output eth_rx_clk, - output eth_tx_clk, - + /* Base clock, buffered */ output base50_clk ); @@ -116,27 +109,27 @@ PLL_ADV #( .CLKOUT0_DIVIDE(f_div), .CLKOUT0_DUTY_CYCLE(0.5), .CLKOUT0_PHASE(0.0), - + .CLKOUT1_DIVIDE(f_div), .CLKOUT1_DUTY_CYCLE(0.5), .CLKOUT1_PHASE(0.0), - + .CLKOUT2_DIVIDE(2*f_div), .CLKOUT2_DUTY_CYCLE(0.5), .CLKOUT2_PHASE(270.0), - + .CLKOUT3_DIVIDE(4*f_div), .CLKOUT3_DUTY_CYCLE(0.5), .CLKOUT3_PHASE(0.0), - + .CLKOUT4_DIVIDE(4*f_mult), .CLKOUT4_DUTY_CYCLE(0.5), .CLKOUT4_PHASE(0.0), - + .CLKOUT5_DIVIDE(2*f_div), .CLKOUT5_DUTY_CYCLE(0.5), .CLKOUT5_PHASE(250.0), - + .COMPENSATION("INTERNAL"), .DIVCLK_DIVIDE(1), .REF_JITTER(0.100), @@ -218,7 +211,7 @@ BUFG bufg_x2_offclk( ); -/* +/* * SDRAM clock */ @@ -251,15 +244,4 @@ ODDR2 #( .S(1'b0) ); -/* - * Ethernet PHY - */ - -always @(posedge base50_clk) - eth_phy_clk_pad <= ~eth_phy_clk_pad; - -/* Let the synthesizer insert the appropriate buffers */ -assign eth_rx_clk = eth_rx_clk_pad; -assign eth_tx_clk = eth_tx_clk_pad; - endmodule -- 2.30.2