-[submodule "extcores/lm32/submodule"]
- path = extcores/lm32/submodule
+[submodule "misoc/lm32/verilog/submodule"]
+ path = misoc/lm32/verilog/submodule
url = https://github.com/m-labs/lm32.git
-[submodule "extcores/mor1kx/submodule"]
- path = extcores/mor1kx/submodule
+[submodule "misoc/mor1kx/verilog"]
+ path = misoc/mor1kx/verilog
url = https://github.com/openrisc/mor1kx.git
[submodule "software/compiler-rt"]
path = software/compiler-rt
+++ /dev/null
-`ifdef LM32_CONFIG_V
-`else
-`define LM32_CONFIG_V
-
-//
-// EXCEPTION VECTORS BASE ADDRESS
-//
-
-// Base address for exception vectors
-`define CFG_EBA_RESET 32'h00000000
-
-// Base address for the debug exception vectors. If the DC_RE flag is
-// set or the at_debug signal is asserted (see CFG_ALTERNATE_EBA) this
-// will also be used for normal exception vectors.
-`define CFG_DEBA_RESET 32'h10000000
-
-// Enable exception vector remapping by external signal
-//`define CFG_ALTERNATE_EBA
-
-
-//
-// ALU OPTIONS
-//
-
-// Enable sign-extension instructions
-`define CFG_SIGN_EXTEND_ENABLED
-
-// Shifter
-// You may either enable the piplined or the multi-cycle barrel
-// shifter. The multi-cycle shifter will stall the pipeline until
-// the result is available after 32 cycles.
-// If both options are disabled, only "right shift by one bit" is
-// available.
-//`define CFG_MC_BARREL_SHIFT_ENABLED
-`define CFG_PL_BARREL_SHIFT_ENABLED
-
-// Multiplier
-// The multiplier is available either in a multi-cycle version or
-// in a pipelined one. The multi-cycle multiplier stalls the pipe
-// for 32 cycles. If both options are disabled, multiply operations
-// are not supported.
-//`define CFG_MC_MULTIPLY_ENABLED
-`define CFG_PL_MULTIPLY_ENABLED
-
-// Enable the multi-cycle divider. Stalls the pipe until the result
-// is ready after 32 cycles. If disabled, the divide operation is not
-// supported.
-`define CFG_MC_DIVIDE_ENABLED
-
-
-//
-// INTERRUPTS
-//
-
-// Enable support for 32 hardware interrupts
-`define CFG_INTERRUPTS_ENABLED
-
-// Enable level-sensitive interrupts. The interrupt line status is
-// reflected in the IP register, which is then read-only.
-`define CFG_LEVEL_SENSITIVE_INTERRUPTS
-
-
-//
-// USER INSTRUCTION
-//
-
-// Enable support for the user opcode.
-//`define CFG_USER_ENABLED
-
-
-//
-// MEMORY MANAGEMENT UNIT
-//
-
-// Enable instruction and data translation lookaside buffers and
-// restricted user mode.
-//`define CFG_MMU_ENABLED
-
-
-//
-// CACHE
-//
-
-// Instruction cache
-`define CFG_ICACHE_ENABLED
-`define CFG_ICACHE_ASSOCIATIVITY 1
-`define CFG_ICACHE_SETS 256
-`define CFG_ICACHE_BYTES_PER_LINE 16
-`define CFG_ICACHE_BASE_ADDRESS 32'h00000000
-`define CFG_ICACHE_LIMIT 32'h7fffffff
-
-// Data cache
-`define CFG_DCACHE_ENABLED
-`define CFG_DCACHE_ASSOCIATIVITY 1
-`define CFG_DCACHE_SETS 256
-`define CFG_DCACHE_BYTES_PER_LINE 16
-`define CFG_DCACHE_BASE_ADDRESS 32'h00000000
-`define CFG_DCACHE_LIMIT 32'h7fffffff
-
-
-//
-// DEBUG OPTION
-//
-
-// Globally enable debugging
-//`define CFG_DEBUG_ENABLED
-
-// Enable the hardware JTAG debugging interface.
-// Note: to use this, there must be a special JTAG module for your
-// device. At the moment, there is only support for the
-// Spartan-6.
-//`define CFG_JTAG_ENABLED
-
-// JTAG UART is a communication channel which uses JTAG to transmit
-// and receive bytes to and from the host computer.
-//`define CFG_JTAG_UART_ENABLED
-
-// Enable reading and writing to the memory and writing CSRs using
-// the JTAG interface.
-//`define CFG_HW_DEBUG_ENABLED
-
-// Number of hardware watchpoints, max. 4
-//`define CFG_WATCHPOINTS 32'h4
-
-// Enable hardware breakpoints
-//`define CFG_ROM_DEBUG_ENABLED
-
-// Number of hardware breakpoints, max. 4
-//`define CFG_BREAKPOINTS 32'h4
-
-// Put the processor into debug mode by an external signal. That is,
-// raise a breakpoint exception. This is useful if you have a debug
-// monitor and a serial line and you want to trap into the monitor on a
-// BREAK symbol on the serial line.
-//`define CFG_EXTERNAL_BREAK_ENABLED
-
-
-//
-// REGISTER FILE
-//
-
-// The following option explicitly infers block RAM for the register
-// file. There is extra logic to avoid parallel writes and reads.
-// Normally, if your synthesizer is smart enough, this should not be
-// necessary because it will automatically infer block RAM for you.
-//`define CFG_EBR_POSEDGE_REGISTER_FILE
-
-// Explicitly infers block RAM, too. But it uses two different clocks,
-// one being shifted by 180deg, for the read and write port. Therefore,
-// no additional logic to avoid the parallel write/reads.
-//`define CFG_EBR_NEGEDGE_REGISTER_FILE
-
-
-//
-// MISCELLANEOUS
-//
-
-// Exceptions on wishbone bus errors
-//`define CFG_BUS_ERRORS_ENABLED
-
-// Enable the cycle counter
-`define CFG_CYCLE_COUNTER_ENABLED
-
-// Embedded instruction ROM using on-chip block RAM
-//`define CFG_IROM_ENABLED
-//`define CFG_IROM_INIT_FILE "NONE"
-//`define CFG_IROM_BASE_ADDRESS 32'h10000000
-//`define CFG_IROM_LIMIT 32'h10000fff
-
-// Embedded data RAM using on-chip block RAM
-//`define CFG_DRAM_ENABLED
-//`define CFG_DRAM_INIT_FILE "NONE"
-//`define CFG_DRAM_BASE_ADDRESS 32'h20000000
-//`define CFG_DRAM_LIMIT 32'h20000fff
-
-// Trace unit
-//`define CFG_TRACE_ENABLED
-
-// Resolve unconditional branches already in the X stage (UNTESTED!)
-//`define CFG_FAST_UNCONDITIONAL_BRANCH
-
-// log2 function
-// If your simulator/synthesizer does not support the $clog2 system
-// function you can use a constant function instead.
-
-function integer clog2;
- input integer value;
- begin
- value = value - 1;
- for (clog2 = 0; value > 0; clog2 = clog2 + 1)
- value = value >> 1;
- end
-endfunction
-
-`define CLOG2 clog2
-
-//`define CLOG2 $clog2
-
-`endif
+++ /dev/null
-Subproject commit 84b3e3ca0ad9535acaef201c1482342871358b08
+++ /dev/null
-Subproject commit 95fc8e432d762e48b42991663cf9d0cdb918e27e
+++ /dev/null
-from migen import *
-from migen.genlib.cdc import MultiReg
-from migen.bank.description import *
-
-
-class GPIOIn(Module, AutoCSR):
- def __init__(self, signal):
- self._in = CSRStatus(flen(signal))
- self.specials += MultiReg(signal, self._in.status)
-
-
-class GPIOOut(Module, AutoCSR):
- def __init__(self, signal):
- self._out = CSRStorage(flen(signal))
- self.comb += signal.eq(self._out.storage)
-
-
-class GPIOInOut(Module):
- def __init__(self, in_signal, out_signal):
- self.submodules.gpio_in = GPIOIn(in_signal)
- self.submodules.gpio_out = GPIOOut(out_signal)
-
- def get_csrs(self):
- return self.gpio_in.get_csrs() + self.gpio_out.get_csrs()
-
-
-class Blinker(Module):
- def __init__(self, signal, divbits=26):
- counter = Signal(divbits)
- self.comb += signal.eq(counter[divbits-1])
- self.sync += counter.eq(counter + 1)
+++ /dev/null
-Unless otherwise noted, LiteEth is copyright (C) 2015 Florent Kermarrec.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-Other authors retain ownership of their contributions. If a submission can
-reasonably be considered independently copyrightable, it's yours and we
-encourage you to claim it with appropriate copyright notices. This submission
-then falls under the "otherwise noted" category. All submissions are strongly
-encouraged to use the two-clause BSD license reproduced above.
+++ /dev/null
- __ _ __ ______ __ __ ____ _
- / / (_) /____ / __/ /_/ / / |/ (_)__ (_)
- / /__/ / __/ -_) _// __/ _ \/ /|_/ / / _ \/ /
- /____/_/\__/\__/___/\__/_//_/_/ /_/_/_//_/_/
-
- Copyright 2012-2015 / EnjoyDigital / M-Labs Ltd
-
- A small footprint and configurable minimal Ethernet core
- powered by Migen
-
-[> Intro
----------
-LiteEthMini is a subset of LiteEth (https://github.com/enjoy-digital/liteeth)
-intended to be used with a CPU and a software stack.
-
-[> Features
------------
-- Ethernet MAC with various various PHYs (GMII, MII, RGMII, Loopback)
-- SRAM storage and wishbone interface
-
-[> Possible improvements
--------------------------
-- add DMA interface to MAC
-- add SGMII PHY
-- ... See below Support and consulting :)
-
-If you want to support these features, please contact us at florent [AT]
-enjoy-digital.fr. You can also contact our partner on the public mailing list
-devel [AT] lists.m-labs.hk.
-
-[> License
------------
-LiteEthMini is released under the very permissive two-clause BSD license. Under
-the terms of this license, you are authorized to use LiteEthMini for closed-source
-proprietary designs.
-Even though we do not require you to do so, those things are awesome, so please
-do them if possible:
- - tell us that you are using LiteEthMini
- - cite LiteEthMini in publications related to research it has helped
- - send us feedback and suggestions for improvements
- - send us bug reports when something goes wrong
- - send us the modifications and improvements you have done to LiteEthMini.
-
-[> Support and consulting
---------------------------
-We love open-source hardware and like sharing our designs with others.
-
-LiteEthMini is mainly developed and maintained by EnjoyDigital.
-
-If you would like to know more about LiteEthMini or if you are already a happy
-user and would like to extend it for your needs, EnjoyDigital can provide standard
-commercial support as well as consulting services.
-
-So feel free to contact us, we'd love to work with you! (and eventually shorten
-the list of the possible improvements :)
-
-[> Contact
-E-mail: florent [AT] enjoy-digital.fr
\ No newline at end of file
+++ /dev/null
-import math
-from collections import OrderedDict
-
-from migen import *
-from migen.genlib.resetsync import AsyncResetSynchronizer
-from migen.genlib.record import *
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.misc import chooser, reverse_bytes, FlipFlop, Counter, WaitTimer
-from migen.flow.actor import *
-from migen.actorlib.structuring import Converter, Pipeline
-from migen.actorlib.fifo import SyncFIFO, AsyncFIFO
-from migen.actorlib.packet import *
-from migen.bank.description import *
-
-class Port:
- def connect(self, port):
- r = [
- Record.connect(self.source, port.sink),
- Record.connect(port.source, self.sink)
- ]
- return r
-
-eth_mtu = 1532
-eth_min_len = 46
-eth_interpacket_gap = 12
-eth_preamble = 0xD555555555555555
-buffer_depth = 2**log2_int(eth_mtu, need_pow2=False)
-
-def eth_phy_description(dw):
- payload_layout = [
- ("data", dw),
- ("last_be", dw//8),
- ("error", dw//8)
- ]
- return EndpointDescription(payload_layout, packetized=True)
-
-
-def eth_mac_description(dw):
- payload_layout = mac_header.get_layout() + [
- ("data", dw),
- ("last_be", dw//8),
- ("error", dw//8)
- ]
- return EndpointDescription(payload_layout, packetized=True)
+++ /dev/null
-from misoc.com.liteethmini.common import *
-from misoc.com.liteethmini.mac.core import LiteEthMACCore
-from misoc.com.liteethmini.mac.frontend.wishbone import LiteEthMACWishboneInterface
-
-
-class LiteEthMAC(Module, AutoCSR):
- def __init__(self, phy, dw,
- interface="wishbone",
- endianness="big",
- with_preamble_crc=True):
- self.submodules.core = LiteEthMACCore(phy, dw, endianness, with_preamble_crc)
- self.csrs = []
- if interface == "wishbone":
- self.submodules.interface = LiteEthMACWishboneInterface(dw, 2, 2)
- self.comb += Port.connect(self.interface, self.core)
- self.ev, self.bus = self.interface.sram.ev, self.interface.bus
- self.csrs = self.interface.get_csrs() + self.core.get_csrs()
- else:
- raise NotImplementedError
-
- def get_csrs(self):
- return self.csrs
+++ /dev/null
-from misoc.com.liteethmini.common import *
-from misoc.com.liteethmini.mac.core import gap, preamble, crc, padding, last_be
-from misoc.com.liteethmini.phy.sim import LiteEthPHYSim
-from misoc.com.liteethmini.phy.mii import LiteEthPHYMII
-
-
-class LiteEthMACCore(Module, AutoCSR):
- def __init__(self, phy, dw, endianness="big",
- with_preamble_crc=True,
- with_padding=True):
- if dw < phy.dw:
- raise ValueError("Core data width({}) must be larger than PHY data width({})".format(dw, phy.dw))
-
- rx_pipeline = [phy]
- tx_pipeline = [phy]
-
- # Interpacket gap
- tx_gap_inserter = gap.LiteEthMACGap(phy.dw)
- rx_gap_checker = gap.LiteEthMACGap(phy.dw, ack_on_gap=True)
- self.submodules += RenameClockDomains(tx_gap_inserter, "eth_tx")
- self.submodules += RenameClockDomains(rx_gap_checker, "eth_rx")
-
- tx_pipeline += [tx_gap_inserter]
- rx_pipeline += [rx_gap_checker]
-
- # Preamble / CRC
- if isinstance(phy, LiteEthPHYSim):
- # In simulation, avoid CRC/Preamble to enable direct connection
- # to the Ethernet tap.
- self._preamble_crc = CSRStatus(reset=1)
- elif with_preamble_crc:
- self._preamble_crc = CSRStatus(reset=1)
- # Preamble insert/check
- preamble_inserter = preamble.LiteEthMACPreambleInserter(phy.dw)
- preamble_checker = preamble.LiteEthMACPreambleChecker(phy.dw)
- self.submodules += RenameClockDomains(preamble_inserter, "eth_tx")
- self.submodules += RenameClockDomains(preamble_checker, "eth_rx")
-
- # CRC insert/check
- crc32_inserter = crc.LiteEthMACCRC32Inserter(eth_phy_description(phy.dw))
- crc32_checker = crc.LiteEthMACCRC32Checker(eth_phy_description(phy.dw))
- self.submodules += RenameClockDomains(crc32_inserter, "eth_tx")
- self.submodules += RenameClockDomains(crc32_checker, "eth_rx")
-
- tx_pipeline += [preamble_inserter, crc32_inserter]
- rx_pipeline += [preamble_checker, crc32_checker]
-
- # Padding
- if with_padding:
- padding_inserter = padding.LiteEthMACPaddingInserter(phy.dw, 60)
- padding_checker = padding.LiteEthMACPaddingChecker(phy.dw, 60)
- self.submodules += RenameClockDomains(padding_inserter, "eth_tx")
- self.submodules += RenameClockDomains(padding_checker, "eth_rx")
-
- tx_pipeline += [padding_inserter]
- rx_pipeline += [padding_checker]
-
- # Delimiters
- if dw != 8:
- tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw)
- rx_last_be = last_be.LiteEthMACRXLastBE(phy.dw)
- self.submodules += RenameClockDomains(tx_last_be, "eth_tx")
- self.submodules += RenameClockDomains(rx_last_be, "eth_rx")
-
- tx_pipeline += [tx_last_be]
- rx_pipeline += [rx_last_be]
-
- # Converters
- if dw != phy.dw:
- reverse = endianness == "big"
- tx_converter = Converter(eth_phy_description(dw),
- eth_phy_description(phy.dw),
- reverse=reverse)
- rx_converter = Converter(eth_phy_description(phy.dw),
- eth_phy_description(dw),
- reverse=reverse)
- self.submodules += RenameClockDomains(tx_converter, "eth_tx")
- self.submodules += RenameClockDomains(rx_converter, "eth_rx")
-
- tx_pipeline += [tx_converter]
- rx_pipeline += [rx_converter]
-
- # Cross Domain Crossing
- if isinstance(phy, LiteEthPHYMII):
- fifo_depth = 8
- else:
- fifo_depth = 64
- tx_cdc = AsyncFIFO(eth_phy_description(dw), fifo_depth)
- rx_cdc = AsyncFIFO(eth_phy_description(dw), fifo_depth)
- self.submodules += RenameClockDomains(tx_cdc, {"write": "sys", "read": "eth_tx"})
- self.submodules += RenameClockDomains(rx_cdc, {"write": "eth_rx", "read": "sys"})
-
- tx_pipeline += [tx_cdc]
- rx_pipeline += [rx_cdc]
-
- # Graph
- self.submodules.tx_pipeline = Pipeline(*reversed(tx_pipeline))
- self.submodules.rx_pipeline = Pipeline(*rx_pipeline)
-
- self.sink, self.source = self.tx_pipeline.sink, self.rx_pipeline.source
+++ /dev/null
-from misoc.com.liteethmini.common import *
-
-
-class LiteEthMACCRCEngine(Module):
- """Cyclic Redundancy Check Engine
-
- Compute next CRC value from last CRC value and data input using
- an optimized asynchronous LFSR.
-
- Parameters
- ----------
- data_width : int
- Width of the data bus.
- width : int
- Width of the CRC.
- polynom : int
- Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
-
- Attributes
- ----------
- data : in
- Data input.
- last : in
- last CRC value.
- next :
- next CRC value.
- """
- def __init__(self, data_width, width, polynom):
- self.data = Signal(data_width)
- self.last = Signal(width)
- self.next = Signal(width)
-
- # # #
-
- def _optimize_eq(l):
- """
- Replace even numbers of XORs in the equation
- with an equivalent XOR
- """
- d = OrderedDict()
- for e in l:
- if e in d:
- d[e] += 1
- else:
- d[e] = 1
- r = []
- for key, value in d.items():
- if value%2 != 0:
- r.append(key)
- return r
-
- # compute and optimize CRC's LFSR
- curval = [[("state", i)] for i in range(width)]
- for i in range(data_width):
- feedback = curval.pop() + [("din", i)]
- for j in range(width-1):
- if (polynom & (1<<(j+1))):
- curval[j] += feedback
- curval[j] = _optimize_eq(curval[j])
- curval.insert(0, feedback)
-
- # implement logic
- for i in range(width):
- xors = []
- for t, n in curval[i]:
- if t == "state":
- xors += [self.last[n]]
- elif t == "din":
- xors += [self.data[n]]
- self.comb += self.next[i].eq(optree("^", xors))
-
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class LiteEthMACCRC32(Module):
- """IEEE 802.3 CRC
-
- Implement an IEEE 802.3 CRC generator/checker.
-
- Parameters
- ----------
- data_width : int
- Width of the data bus.
-
- Attributes
- ----------
- d : in
- Data input.
- value : out
- CRC value (used for generator).
- error : out
- CRC error (used for checker).
- """
- width = 32
- polynom = 0x04C11DB7
- init = 2**width-1
- check = 0xC704DD7B
- def __init__(self, data_width):
- self.data = Signal(data_width)
- self.value = Signal(self.width)
- self.error = Signal()
-
- # # #
-
- self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom)
- reg = Signal(self.width, reset=self.init)
- self.sync += reg.eq(self.engine.next)
- self.comb += [
- self.engine.data.eq(self.data),
- self.engine.last.eq(reg),
-
- self.value.eq(~reg[::-1]),
- self.error.eq(self.engine.next != self.check)
- ]
-
-
-class LiteEthMACCRCInserter(Module):
- """CRC Inserter
-
- Append a CRC at the end of each packet.
-
- Parameters
- ----------
- description : description
- description of the dataflow.
-
- Attributes
- ----------
- sink : in
- Packets input without CRC.
- source : out
- Packets output with CRC.
- """
- def __init__(self, crc_class, description):
- self.sink = sink = Sink(description)
- self.source = source = Source(description)
- self.busy = Signal()
-
- # # #
-
- dw = flen(sink.data)
- crc = crc_class(dw)
- fsm = FSM(reset_state="IDLE")
- self.submodules += crc, fsm
-
- fsm.act("IDLE",
- crc.reset.eq(1),
- sink.ack.eq(1),
- If(sink.stb & sink.sop,
- sink.ack.eq(0),
- NextState("COPY"),
- )
- )
- fsm.act("COPY",
- crc.ce.eq(sink.stb & source.ack),
- crc.data.eq(sink.data),
- Record.connect(sink, source),
- source.eop.eq(0),
- If(sink.stb & sink.eop & source.ack,
- NextState("INSERT"),
- )
- )
- ratio = crc.width//dw
- if ratio > 1:
- cnt = Signal(max=ratio, reset=ratio-1)
- cnt_done = Signal()
- fsm.act("INSERT",
- source.stb.eq(1),
- chooser(crc.value, cnt, source.data, reverse=True),
- If(cnt_done,
- source.eop.eq(1),
- If(source.ack, NextState("IDLE"))
- )
- )
- self.comb += cnt_done.eq(cnt == 0)
- self.sync += \
- If(fsm.ongoing("IDLE"),
- cnt.eq(cnt.reset)
- ).Elif(fsm.ongoing("INSERT") & ~cnt_done,
- cnt.eq(cnt - source.ack)
- )
- else:
- fsm.act("INSERT",
- source.stb.eq(1),
- source.eop.eq(1),
- source.data.eq(crc.value),
- If(source.ack, NextState("IDLE"))
- )
- self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
-
-
-class LiteEthMACCRC32Inserter(LiteEthMACCRCInserter):
- def __init__(self, description):
- LiteEthMACCRCInserter.__init__(self, LiteEthMACCRC32, description)
-
-
-class LiteEthMACCRCChecker(Module):
- """CRC Checker
-
- Check CRC at the end of each packet.
-
- Parameters
- ----------
- description : description
- description of the dataflow.
-
- Attributes
- ----------
- sink : in
- Packets input with CRC.
- source : out
- Packets output without CRC and "error" set to 0
- on eop when CRC OK / set to 1 when CRC KO.
- """
- def __init__(self, crc_class, description):
- self.sink = sink = Sink(description)
- self.source = source = Source(description)
- self.busy = Signal()
-
- # # #
-
- dw = flen(sink.data)
- crc = crc_class(dw)
- self.submodules += crc
- ratio = crc.width//dw
-
- error = Signal()
- fifo = InsertReset(SyncFIFO(description, ratio + 1))
- self.submodules += fifo
-
- fsm = FSM(reset_state="RESET")
- self.submodules += fsm
-
- fifo_in = Signal()
- fifo_out = Signal()
- fifo_full = Signal()
-
- self.comb += [
- fifo_full.eq(fifo.fifo.level == ratio),
- fifo_in.eq(sink.stb & (~fifo_full | fifo_out)),
- fifo_out.eq(source.stb & source.ack),
-
- Record.connect(sink, fifo.sink),
- fifo.sink.stb.eq(fifo_in),
- self.sink.ack.eq(fifo_in),
-
- source.stb.eq(sink.stb & fifo_full),
- source.sop.eq(fifo.source.sop),
- source.eop.eq(sink.eop),
- fifo.source.ack.eq(fifo_out),
- source.payload.eq(fifo.source.payload),
-
- source.error.eq(sink.error | crc.error),
- ]
-
- fsm.act("RESET",
- crc.reset.eq(1),
- fifo.reset.eq(1),
- NextState("IDLE"),
- )
- self.comb += crc.data.eq(sink.data)
- fsm.act("IDLE",
- If(sink.stb & sink.sop & sink.ack,
- crc.ce.eq(1),
- NextState("COPY")
- )
- )
- fsm.act("COPY",
- If(sink.stb & sink.ack,
- crc.ce.eq(1),
- If(sink.eop,
- NextState("RESET")
- )
- )
- )
- self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
-
-
-class LiteEthMACCRC32Checker(LiteEthMACCRCChecker):
- def __init__(self, description):
- LiteEthMACCRCChecker.__init__(self, LiteEthMACCRC32, description)
+++ /dev/null
-from misoc.com.liteethmini.common import *
-
-class LiteEthMACGap(Module):
- def __init__(self, dw, ack_on_gap=False):
- self.sink = sink = Sink(eth_phy_description(dw))
- self.source = source = Source(eth_phy_description(dw))
-
- # # #
-
- gap = math.ceil(eth_interpacket_gap/(dw//8))
- self.submodules.counter = counter = Counter(max=gap)
-
- self.submodules.fsm = fsm = FSM(reset_state="COPY")
- fsm.act("COPY",
- counter.reset.eq(1),
- Record.connect(sink, source),
- If(sink.stb & sink.eop & sink.ack,
- NextState("GAP")
- )
- )
- fsm.act("GAP",
- counter.ce.eq(1),
- sink.ack.eq(int(ack_on_gap)),
- If(counter.value == (gap-1),
- NextState("COPY")
- )
- )
+++ /dev/null
-from misoc.com.liteethmini.common import *
-
-
-class LiteEthMACTXLastBE(Module):
- def __init__(self, dw):
- self.sink = sink = Sink(eth_phy_description(dw))
- self.source = source = Source(eth_phy_description(dw))
-
- # # #
-
- ongoing = Signal()
- self.sync += \
- If(sink.stb & sink.ack,
- If(sink.sop,
- ongoing.eq(1)
- ).Elif(sink.last_be,
- ongoing.eq(0)
- )
- )
- self.comb += [
- source.stb.eq(sink.stb & (sink.sop | ongoing)),
- source.sop.eq(sink.sop),
- source.eop.eq(sink.last_be),
- source.data.eq(sink.data),
- sink.ack.eq(source.ack)
- ]
-
-
-class LiteEthMACRXLastBE(Module):
- def __init__(self, dw):
- self.sink = sink = Sink(eth_phy_description(dw))
- self.source = source = Source(eth_phy_description(dw))
-
- # # #
-
- self.comb += [
- source.stb.eq(sink.stb),
- source.sop.eq(sink.sop),
- source.eop.eq(sink.eop),
- source.data.eq(sink.data),
- source.last_be.eq(sink.eop),
- sink.ack.eq(source.ack)
- ]
+++ /dev/null
-from misoc.com.liteethmini.common import *
-
-
-class LiteEthMACPaddingInserter(Module):
- def __init__(self, dw, padding):
- self.sink = sink = Sink(eth_phy_description(dw))
- self.source = source = Source(eth_phy_description(dw))
-
- # # #
-
- padding_limit = math.ceil(padding/(dw/8))-1
-
- self.submodules.counter = counter = Counter(16, reset=1)
- counter_done = Signal()
- self.comb += [
- counter.reset.eq(sink.stb & sink.sop & sink.ack),
- counter.ce.eq(source.stb & source.ack),
- counter_done.eq(counter.value >= padding_limit),
- ]
-
- self.submodules.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- Record.connect(sink, source),
- If(source.stb & source.ack,
- counter.ce.eq(1),
- If(sink.eop,
- If(~counter_done,
- source.eop.eq(0),
- NextState("PADDING")
- )
- )
- )
- )
- fsm.act("PADDING",
- source.stb.eq(1),
- source.eop.eq(counter_done),
- source.data.eq(0),
- If(source.ack,
- If(counter_done,
- NextState("IDLE")
- )
- )
- )
-
-
-class LiteEthMACPaddingChecker(Module):
- def __init__(self, dw, packet_min_length):
- self.sink = sink = Sink(eth_phy_description(dw))
- self.source = source = Source(eth_phy_description(dw))
-
- # # #
-
- # XXX see if we should drop the packet when
- # payload size < minimum ethernet payload size
- self.comb += Record.connect(sink, source)
-
+++ /dev/null
-from misoc.com.liteethmini.common import *
-
-
-class LiteEthMACPreambleInserter(Module):
- def __init__(self, dw):
- self.sink = Sink(eth_phy_description(dw))
- self.source = Source(eth_phy_description(dw))
-
- # # #
-
- preamble = Signal(64, reset=eth_preamble)
- cnt_max = (64//dw)-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.data),
- If(cnt == cnt_max,
- If(self.source.ack, NextState("COPY"))
- ).Else(
- inc_cnt.eq(self.source.ack)
- )
- )
-
- self.comb += [
- self.source.data.eq(self.sink.data),
- self.source.last_be.eq(self.sink.last_be)
- ]
- fsm.act("COPY",
- Record.connect(self.sink, self.source, leave_out=set(["data", "last_be"])),
- self.source.sop.eq(0),
-
- If(self.sink.stb & self.sink.eop & self.source.ack,
- NextState("IDLE"),
- )
- )
-
-
-class LiteEthMACPreambleChecker(Module):
- def __init__(self, dw):
- self.sink = Sink(eth_phy_description(dw))
- self.source = Source(eth_phy_description(dw))
-
- # # #
-
- preamble = Signal(64, reset=eth_preamble)
- cnt_max = (64//dw) - 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(dw)
- match = Signal()
- self.comb += [
- chooser(preamble, cnt, ref),
- match.eq(self.sink.data == 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)
- )
- )
- )
- self.comb += [
- self.source.data.eq(self.sink.data),
- self.source.last_be.eq(self.sink.last_be)
- ]
- fsm.act("COPY",
- Record.connect(self.sink, self.source, leave_out=set(["data", "last_be"])),
- 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"),
- )
- )
+++ /dev/null
-from misoc.com.liteethmini.common import *
-
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-
-
-class LiteEthMACSRAMWriter(Module, AutoCSR):
- def __init__(self, dw, depth, nslots=2):
- self.sink = sink = Sink(eth_phy_description(dw))
- 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
- increment = Signal(3)
- self.comb += \
- If(sink.last_be[3],
- increment.eq(1)
- ).Elif(sink.last_be[2],
- increment.eq(2)
- ).Elif(sink.last_be[1],
- increment.eq(3)
- ).Else(
- increment.eq(4)
- )
- counter = Counter(lengthbits, increment=increment)
- self.submodules += counter
-
- # slot computation
- slot = Counter(slotbits)
- self.submodules += slot
-
- ongoing = 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",
- If(sink.stb & sink.sop,
- If(fifo.sink.ack,
- ongoing.eq(1),
- counter.ce.eq(1),
- NextState("WRITE")
- )
- )
- )
- fsm.act("WRITE",
- counter.ce.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",
- counter.reset.eq(1),
- NextState("IDLE")
- )
- self.comb += [
- fifo.sink.slot.eq(slot.value),
- fifo.sink.length.eq(counter.value)
- ]
- fsm.act("TERMINATE",
- counter.reset.eq(1),
- slot.ce.eq(1),
- fifo.sink.stb.eq(1),
- NextState("IDLE")
- )
- self.comb += [
- fifo.source.ack.eq(self.ev.available.clear),
- self.ev.available.trigger.eq(fifo.source.stb),
- self._slot.status.eq(fifo.source.slot),
- self._length.status.eq(fifo.source.length),
- ]
-
- # memory
- mems = [None]*nslots
- ports = [None]*nslots
- for n in range(nslots):
- mems[n] = Memory(dw, 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(counter.value[2:]),
- ports[n].dat_w.eq(sink.data),
- If(sink.stb & ongoing,
- ports[n].we.eq(0xf)
- )
- ]
- self.comb += Case(slot.value, cases)
-
-
-class LiteEthMACSRAMReader(Module, AutoCSR):
- def __init__(self, dw, depth, nslots=2):
- self.source = source = Source(eth_phy_description(dw))
-
- 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.sink.stb.eq(self._start.re),
- fifo.sink.slot.eq(self._slot.storage),
- fifo.sink.length.eq(self._length.storage),
- self._ready.status.eq(fifo.sink.ack)
- ]
-
- # length computation
- self.submodules.counter = counter = Counter(lengthbits, increment=4)
-
- # fsm
- first = Signal()
- last = Signal()
- last_d = Signal()
-
- fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
-
- fsm.act("IDLE",
- counter.reset.eq(1),
- If(fifo.source.stb,
- NextState("CHECK")
- )
- )
- fsm.act("CHECK",
- If(~last_d,
- NextState("SEND"),
- ).Else(
- NextState("END"),
- )
- )
- length_lsb = fifo.source.length[0:2]
- self.comb += [
- 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)
- )
- )
- ]
- fsm.act("SEND",
- source.stb.eq(1),
- source.sop.eq(first),
- source.eop.eq(last),
- If(source.ack,
- counter.ce.eq(~last),
- NextState("CHECK")
- )
- )
- fsm.act("END",
- fifo.source.ack.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((counter.value + 4) >= fifo.source.length)
- self.sync += last_d.eq(last)
-
- # memory
- rd_slot = fifo.source.slot
-
- mems = [None]*nslots
- ports = [None]*nslots
- for n in range(nslots):
- mems[n] = Memory(dw, 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(counter.value[2:])
- cases[n] = [source.data.eq(port.dat_r)]
- self.comb += Case(rd_slot, cases)
-
-
-class LiteEthMACSRAM(Module, AutoCSR):
- def __init__(self, dw, depth, nrxslots, ntxslots):
- self.submodules.writer = LiteEthMACSRAMWriter(dw, depth, nrxslots)
- self.submodules.reader = LiteEthMACSRAMReader(dw, depth, ntxslots)
- self.submodules.ev = SharedIRQ(self.writer.ev, self.reader.ev)
- self.sink, self.source = self.writer.sink, self.reader.source
+++ /dev/null
-from misoc.com.liteethmini.common import *
-from misoc.com.liteethmini.mac.frontend import sram
-
-from migen.bus import wishbone
-from migen.fhdl.simplify import FullMemoryWE
-
-
-class LiteEthMACWishboneInterface(Module, AutoCSR):
- def __init__(self, dw, nrxslots=2, ntxslots=2):
- self.sink = Sink(eth_phy_description(dw))
- self.source = Source(eth_phy_description(dw))
- self.bus = wishbone.Interface()
-
- # # #
-
- # storage in SRAM
- sram_depth = buffer_depth//(dw//8)
- self.submodules.sram = sram.LiteEthMACSRAM(dw, sram_depth, nrxslots, ntxslots)
- self.comb += [
- Record.connect(self.sink, self.sram.sink),
- Record.connect(self.sram.source, self.source)
- ]
-
- # Wishbone interface
- wb_rx_sram_ifs = [wishbone.SRAM(self.sram.writer.mems[n], read_only=True)
- for n in range(nrxslots)]
- # TODO: FullMemoryWE should move to Mibuild
- 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
+++ /dev/null
-from misoc.com.liteethmini.common import *
-
-
-def LiteEthPHY(clock_pads, pads, clk_freq=None, **kwargs):
- # Autodetect PHY
- if hasattr(pads, "source_stb"):
- # This is a simulation PHY
- from misoc.com.liteethmini.phy.sim import LiteEthPHYSim
- return LiteEthPHYSim(pads)
- elif hasattr(clock_pads, "gtx") and flen(pads.tx_data) == 8:
- if hasattr(clock_pads, "tx"):
- # This is a 10/100/1G PHY
- from misoc.com.liteethmini.phy.gmii_mii import LiteEthPHYGMIIMII
- return LiteEthPHYGMIIMII(clock_pads, pads, clk_freq=clk_freq, **kwargs)
- else:
- # This is a pure 1G PHY
- from misoc.com.liteethmini.phy.gmii import LiteEthPHYGMII
- return LiteEthPHYGMII(clock_pads, pads, **kwargs)
- elif hasattr(pads, "rx_ctl"):
- # This is a 10/100/1G RGMII PHY
- raise ValueError("RGMII PHYs are specific to vendors (for now), use direct instantiation")
- elif flen(pads.tx_data) == 4:
- # This is a MII PHY
- from misoc.com.liteethmini.phy.mii import LiteEthPHYMII
- return LiteEthPHYMII(clock_pads, pads, **kwargs)
- else:
- raise ValueError("Unable to autodetect PHY from platform file, use direct instantiation")
+++ /dev/null
-from migen.genlib.io import DDROutput
-
-from misoc.com.liteethmini.common import *
-
-
-class LiteEthPHYGMIITX(Module):
- def __init__(self, pads, pads_register=True):
- self.sink = sink = Sink(eth_phy_description(8))
-
- # # #
-
- if hasattr(pads, "tx_er"):
- self.sync += pads.tx_er.eq(0)
- pads_eq = [
- pads.tx_en.eq(sink.stb),
- pads.tx_data.eq(sink.data)
- ]
- if pads_register:
- self.sync += pads_eq
- else:
- self.comb += pads_eq
- self.comb += sink.ack.eq(1)
-
-
-class LiteEthPHYGMIIRX(Module):
- def __init__(self, pads):
- self.source = source = Source(eth_phy_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.data.eq(pads.rx_data)
- ]
- self.comb += source.eop.eq(eop)
-
-
-class LiteEthPHYGMIICRG(Module, AutoCSR):
- def __init__(self, clock_pads, pads, with_hw_init_reset, mii_mode=0):
- self._reset = CSRStorage()
-
- # # #
-
- self.clock_domains.cd_eth_rx = ClockDomain()
- self.clock_domains.cd_eth_tx = ClockDomain()
-
- # RX : Let the synthesis tool insert the appropriate clock buffer
- self.comb += self.cd_eth_rx.clk.eq(clock_pads.rx)
-
- # TX : GMII: Drive clock_pads.gtx, clock_pads.tx unused
- # MII: Use PHY clock_pads.tx as eth_tx_clk, do not drive clock_pads.gtx
- self.specials += DDROutput(1, mii_mode, clock_pads.gtx, ClockSignal("eth_tx"))
- # XXX Xilinx specific, replace BUFGMUX with a generic clock buffer?
- self.specials += Instance("BUFGMUX",
- i_I0=self.cd_eth_rx.clk,
- i_I1=clock_pads.tx,
- i_S=mii_mode,
- o_O=self.cd_eth_tx.clk)
-
- if with_hw_init_reset:
- reset = Signal()
- counter_done = Signal()
- self.submodules.counter = counter = Counter(max=512)
- self.comb += [
- counter_done.eq(counter.value == 256),
- counter.ce.eq(~counter_done),
- reset.eq(~counter_done | self._reset.storage)
- ]
- else:
- 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 LiteEthPHYGMII(Module, AutoCSR):
- def __init__(self, clock_pads, pads, with_hw_init_reset=True):
- self.dw = 8
- self.submodules.crg = LiteEthPHYGMIICRG(clock_pads,
- pads,
- with_hw_init_reset)
- self.submodules.tx = RenameClockDomains(LiteEthPHYGMIITX(pads),
- "eth_tx")
- self.submodules.rx = RenameClockDomains(LiteEthPHYGMIIRX(pads),
- "eth_rx")
- self.sink, self.source = self.tx.sink, self.rx.source
+++ /dev/null
-from migen.genlib.io import DDROutput
-from migen.flow.plumbing import Multiplexer, Demultiplexer
-from migen.genlib.cdc import PulseSynchronizer
-
-from misoc.com.liteethmini.common import *
-
-from misoc.com.liteethmini.phy.gmii import LiteEthPHYGMIICRG
-from misoc.com.liteethmini.phy.mii import LiteEthPHYMIITX, LiteEthPHYMIIRX
-from misoc.com.liteethmini.phy.gmii import LiteEthPHYGMIITX, LiteEthPHYGMIIRX
-
-modes = {
- "GMII": 0,
- "MII": 1
-}
-
-tx_pads_layout = [("tx_er", 1), ("tx_en", 1), ("tx_data", 8)]
-rx_pads_layout = [("rx_er", 1), ("dv", 1), ("rx_data", 8)]
-
-
-class LiteEthPHYGMIIMIITX(Module):
- def __init__(self, pads, mode):
- self.sink = sink = Sink(eth_phy_description(8))
-
- # # #
-
- gmii_tx_pads = Record(tx_pads_layout)
- gmii_tx = LiteEthPHYGMIITX(gmii_tx_pads, pads_register=False)
- self.submodules += gmii_tx
-
- mii_tx_pads = Record(tx_pads_layout)
- mii_tx = LiteEthPHYMIITX(mii_tx_pads, pads_register=False)
- self.submodules += mii_tx
-
- demux = Demultiplexer(eth_phy_description(8), 2)
- self.submodules += demux
- self.comb += [
- demux.sel.eq(mode == modes["MII"]),
- Record.connect(sink, demux.sink),
- Record.connect(demux.source0, gmii_tx.sink),
- Record.connect(demux.source1, mii_tx.sink),
- ]
-
- if hasattr(pads, "tx_er"):
- self.comb += pads.tx_er.eq(0)
- self.sync += [
- If(mode == modes["MII"],
- pads.tx_en.eq(mii_tx_pads.tx_en),
- pads.tx_data.eq(mii_tx_pads.tx_data),
- ).Else(
- pads.tx_en.eq(gmii_tx_pads.tx_en),
- pads.tx_data.eq(gmii_tx_pads.tx_data),
- )
- ]
-
-
-class LiteEthPHYGMIIMIIRX(Module):
- def __init__(self, pads, mode):
- self.source = source = Source(eth_phy_description(8))
-
- # # #
-
- pads_d = Record(rx_pads_layout)
- self.sync += [
- pads_d.dv.eq(pads.dv),
- pads_d.rx_data.eq(pads.rx_data)
- ]
-
- gmii_rx = LiteEthPHYGMIIRX(pads_d)
- self.submodules += gmii_rx
-
- mii_rx = LiteEthPHYMIIRX(pads_d)
- self.submodules += mii_rx
-
- mux = Multiplexer(eth_phy_description(8), 2)
- self.submodules += mux
- self.comb += [
- mux.sel.eq(mode == modes["MII"]),
- Record.connect(gmii_rx.source, mux.sink0),
- Record.connect(mii_rx.source, mux.sink1),
- Record.connect(mux.source, source)
- ]
-
-
-class LiteEthGMIIMIIModeDetection(Module, AutoCSR):
- def __init__(self, clk_freq):
- self.mode = Signal()
- self._mode = CSRStatus()
-
- # # #
-
- mode = Signal()
- update_mode = Signal()
- self.sync += \
- If(update_mode,
- self.mode.eq(mode)
- )
- self.comb += self._mode.status.eq(self.mode)
-
- # Principle:
- # sys_clk >= 125MHz
- # eth_rx <= 125Mhz
- # We generate ticks every 1024 clock cycles in eth_rx domain
- # and measure ticks period in sys_clk domain.
-
- # Generate a tick every 1024 clock cycles (eth_rx clock domain)
- eth_tick = Signal()
- eth_counter = Signal(10)
- self.sync.eth_rx += eth_counter.eq(eth_counter + 1)
- self.comb += eth_tick.eq(eth_counter == 0)
-
- # Synchronize tick (sys clock domain)
- sys_tick = Signal()
- eth_ps = PulseSynchronizer("eth_rx", "sys")
- self.comb += [
- eth_ps.i.eq(eth_tick),
- sys_tick.eq(eth_ps.o)
- ]
- self.submodules += eth_ps
-
- # sys_clk domain counter
- sys_counter = Counter(24)
- self.submodules += sys_counter
-
- fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
-
- fsm.act("IDLE",
- sys_counter.reset.eq(1),
- If(sys_tick,
- NextState("COUNT")
- )
- )
- fsm.act("COUNT",
- sys_counter.ce.eq(1),
- If(sys_tick,
- NextState("DETECTION")
- )
- )
- fsm.act("DETECTION",
- update_mode.eq(1),
- # if freq < 125MHz-5% use MII mode
- If(sys_counter.value > int((clk_freq/125000000)*1024*1.05),
- mode.eq(1)
- # if freq >= 125MHz-5% use GMII mode
- ).Else(
- mode.eq(0)
- ),
- NextState("IDLE")
- )
-
-
-class LiteEthPHYGMIIMII(Module, AutoCSR):
- def __init__(self, clock_pads, pads, clk_freq, with_hw_init_reset=True):
- self.dw = 8
- # Note: we can use GMII CRG since it also handles tx clock pad used for MII
- self.submodules.mode_detection = LiteEthGMIIMIIModeDetection(clk_freq)
- mode = self.mode_detection.mode
- self.submodules.crg = LiteEthPHYGMIICRG(clock_pads, pads, with_hw_init_reset, mode == modes["MII"])
- self.submodules.tx = RenameClockDomains(LiteEthPHYGMIIMIITX(pads, mode), "eth_tx")
- self.submodules.rx = RenameClockDomains(LiteEthPHYGMIIMIIRX(pads, mode), "eth_rx")
- self.sink, self.source = self.tx.sink, self.rx.source
+++ /dev/null
-from misoc.com.liteethmini.common import *
-from misoc.com.liteethmini.generic import *
-
-
-class LiteEthPHYLoopbackCRG(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 LiteEthPHYLoopback(Module, AutoCSR):
- def __init__(self):
- self.dw = 8
- self.submodules.crg = LiteEthLoopbackPHYCRG()
- self.sink = sink = Sink(eth_phy_description(8))
- self.source = source = Source(eth_phy_description(8))
- self.comb += Record.connect(self.sink, self.source)
+++ /dev/null
-from misoc.com.liteethmini.common import *
-
-
-def converter_description(dw):
- payload_layout = [("data", dw)]
- return EndpointDescription(payload_layout, packetized=True)
-
-
-class LiteEthPHYMIITX(Module):
- def __init__(self, pads, pads_register=True):
- self.sink = sink = Sink(eth_phy_description(8))
-
- # # #
-
- if hasattr(pads, "tx_er"):
- self.sync += pads.tx_er.eq(0)
- converter = Converter(converter_description(8),
- converter_description(4))
- self.submodules += converter
- self.comb += [
- converter.sink.stb.eq(sink.stb),
- converter.sink.data.eq(sink.data),
- sink.ack.eq(converter.sink.ack),
- converter.source.ack.eq(1)
- ]
- pads_eq = [
- pads.tx_en.eq(converter.source.stb),
- pads.tx_data.eq(converter.source.data)
- ]
- if pads_register:
- self.sync += pads_eq
- else:
- self.comb += pads_eq
-
-
-class LiteEthPHYMIIRX(Module):
- def __init__(self, pads):
- self.source = source = Source(eth_phy_description(8))
-
- # # #
-
- sop = FlipFlop(reset=1)
- self.submodules += sop
-
- converter = Converter(converter_description(4),
- converter_description(8))
- converter = InsertReset(converter)
- self.submodules += converter
-
- self.sync += [
- converter.reset.eq(~pads.dv),
- converter.sink.stb.eq(1),
- converter.sink.data.eq(pads.rx_data)
- ]
- self.comb += [
- sop.reset.eq(~pads.dv),
- sop.ce.eq(pads.dv),
- converter.sink.sop.eq(sop.q),
- converter.sink.eop.eq(~pads.dv)
- ]
- self.comb += Record.connect(converter.source, source)
-
-
-class LiteEthPHYMIICRG(Module, AutoCSR):
- def __init__(self, clock_pads, pads, with_hw_init_reset):
- self._reset = CSRStorage()
-
- # # #
-
- if hasattr(clock_pads, "phy"):
- 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)
-
- if with_hw_init_reset:
- reset = Signal()
- counter_done = Signal()
- self.submodules.counter = counter = Counter(max=512)
- self.comb += [
- counter_done.eq(counter.value == 256),
- counter.ce.eq(~counter_done),
- reset.eq(~counter_done | self._reset.storage)
- ]
- else:
- 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 LiteEthPHYMII(Module, AutoCSR):
- def __init__(self, clock_pads, pads, with_hw_init_reset=True):
- self.dw = 8
- self.submodules.crg = LiteEthPHYMIICRG(clock_pads, pads, with_hw_init_reset)
- self.submodules.tx = RenameClockDomains(LiteEthPHYMIITX(pads), "eth_tx")
- self.submodules.rx = RenameClockDomains(LiteEthPHYMIIRX(pads), "eth_rx")
- self.sink, self.source = self.tx.sink, self.rx.source
+++ /dev/null
-# RGMII PHY for Spartan-6
-
-from migen.genlib.io import DDROutput
-from migen.genlib.misc import WaitTimer
-from migen.genlib.fsm import FSM, NextState
-
-from misoc.com.liteethmini.common import *
-
-
-class LiteEthPHYRGMIITX(Module):
- def __init__(self, pads, pads_register=True):
- self.sink = sink = Sink(eth_phy_description(8))
-
- # # #
-
- self.specials += Instance("ODDR2",
- p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="ASYNC",
- i_C0=ClockSignal("eth_tx"), i_C1=~ClockSignal("eth_tx"),
- i_CE=1, i_S=0, i_R=0,
- i_D0=sink.stb, i_D1=sink.stb, o_Q=pads.tx_ctl,
- )
- for i in range(4):
- self.specials += Instance("ODDR2",
- p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="ASYNC",
- i_C0=ClockSignal("eth_tx"), i_C1=~ClockSignal("eth_tx"),
- i_CE=1, i_S=0, i_R=0,
- i_D0=sink.data[i], i_D1=sink.data[4+i], o_Q=pads.tx_data[i],
- )
- self.comb += sink.ack.eq(1)
-
-
-class LiteEthPHYRGMIIRX(Module):
- def __init__(self, pads):
- self.source = source = Source(eth_phy_description(8))
-
- # # #
-
- rx_ctl = Signal()
- rx_data = Signal(8)
-
- self.specials += Instance("IDDR2",
- p_DDR_ALIGNMENT="C0", p_INIT_Q0=0, p_INIT_Q1=0, p_SRTYPE="ASYNC",
- i_C0=ClockSignal("eth_rx"), i_C1=~ClockSignal("eth_rx"),
- i_CE=1, i_S=0, i_R=0,
- i_D=pads.rx_ctl, o_Q1=rx_ctl,
- )
- for i in range(4):
- self.specials += Instance("IDDR2",
- p_DDR_ALIGNMENT="C0", p_INIT_Q0=0, p_INIT_Q1=0, p_SRTYPE="ASYNC",
- i_C0=ClockSignal("eth_rx"), i_C1=~ClockSignal("eth_rx"),
- i_CE=1, i_S=0, i_R=0,
- i_D=pads.rx_data[i], o_Q0=rx_data[4+i], o_Q1=rx_data[i],
- )
-
-
- rx_ctl_d = Signal()
- self.sync += rx_ctl_d.eq(rx_ctl)
-
- sop = Signal()
- eop = Signal()
- self.comb += [
- sop.eq(rx_ctl & ~rx_ctl_d),
- eop.eq(~rx_ctl & rx_ctl_d)
- ]
- self.sync += [
- source.stb.eq(rx_ctl),
- source.sop.eq(sop),
- source.data.eq(rx_data)
- ]
- self.comb += source.eop.eq(eop)
-
-
-class LiteEthPHYRGMIICRG(Module, AutoCSR):
- def __init__(self, clock_pads, pads, with_hw_init_reset):
- self._reset = CSRStorage()
-
- # # #
-
- self.clock_domains.cd_eth_rx = ClockDomain()
- self.clock_domains.cd_eth_tx = ClockDomain()
-
-
- # RX
- dcm_reset = Signal()
- dcm_locked = Signal()
-
- timer = WaitTimer(1024)
- fsm = FSM(reset_state="DCM_RESET")
- self.submodules += timer, fsm
-
- fsm.act("DCM_RESET",
- dcm_reset.eq(1),
- timer.wait.eq(1),
- If(timer.done,
- timer.wait.eq(0),
- NextState("DCM_WAIT")
- )
- )
- fsm.act("DCM_WAIT",
- timer.wait.eq(1),
- If(timer.done,
- NextState("DCM_CHECK_LOCK")
- )
- )
- fsm.act("DCM_CHECK_LOCK",
- If(~dcm_locked,
- NextState("DCM_RESET")
- )
- )
-
- clk90_rx = Signal()
- clk0_rx = Signal()
- clk0_rx_bufg = Signal()
- self.specials += Instance("DCM",
- i_CLKIN=clock_pads.rx,
- i_CLKFB=clk0_rx_bufg,
- o_CLK0=clk0_rx,
- o_CLK90=clk90_rx,
- o_LOCKED=dcm_locked,
- i_PSEN=0,
- i_PSCLK=0,
- i_PSINCDEC=0,
- i_RST=dcm_reset
- )
-
- self.specials += Instance("BUFG", i_I=clk0_rx, o_O=clk0_rx_bufg)
- self.specials += Instance("BUFG", i_I=clk90_rx, o_O=self.cd_eth_rx.clk)
-
- # TX
- self.specials += DDROutput(1, 0, clock_pads.tx, ClockSignal("eth_tx"))
- self.specials += Instance("BUFG", i_I=self.cd_eth_rx.clk, o_O=self.cd_eth_tx.clk)
-
- # Reset
- if with_hw_init_reset:
- reset = Signal()
- counter_done = Signal()
- self.submodules.counter = counter = Counter(max=512)
- self.comb += [
- counter_done.eq(counter.value == 256),
- counter.ce.eq(~counter_done),
- reset.eq(~counter_done | self._reset.storage)
- ]
- else:
- 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 LiteEthPHYRGMII(Module, AutoCSR):
- def __init__(self, clock_pads, pads, with_hw_init_reset=True):
- self.dw = 8
- self.submodules.crg = LiteEthPHYRGMIICRG(clock_pads,
- pads,
- with_hw_init_reset)
- self.submodules.tx = RenameClockDomains(LiteEthPHYRGMIITX(pads),
- "eth_tx")
- self.submodules.rx = RenameClockDomains(LiteEthPHYRGMIIRX(pads),
- "eth_rx")
- self.sink, self.source = self.tx.sink, self.rx.source
+++ /dev/null
-import os
-
-from misoc.com.liteethmini.common import *
-
-
-class LiteEthPHYSimCRG(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 LiteEthPHYSim(Module, AutoCSR):
- def __init__(self, pads, tap="tap0", ip_address="192.168.0.14"):
- self.dw = 8
- self.submodules.crg = LiteEthPHYSimCRG()
- self.sink = sink = Sink(eth_phy_description(8))
- self.source = source = Source(eth_phy_description(8))
- self.tap = tap
- self.ip_address = ip_address
-
- self.comb += [
- pads.source_stb.eq(self.sink.stb),
- pads.source_data.eq(self.sink.data),
- self.sink.ack.eq(1)
- ]
-
- self.sync += [
- self.source.stb.eq(pads.sink_stb),
- self.source.sop.eq(pads.sink_stb & ~self.source.stb),
- self.source.data.eq(pads.sink_data),
- ]
- self.comb += [
- self.source.eop.eq(~pads.sink_stb & self.source.stb),
- ]
-
- # XXX avoid use of os.system
- os.system("openvpn --mktun --dev {}".format(self.tap))
- os.system("ifconfig {} {} up".format(self.tap, self.ip_address))
- os.system("mknod /dev/net/{} c 10 200".format(self.tap))
-
- def do_exit(self, *args, **kwargs):
- # XXX avoid use of os.system
- os.system("rm -f /dev/net/{}".format(self.tap))
- os.system("openvpn --rmtun --dev {}".format(self.tap))
+++ /dev/null
-from migen import *
-from migen.bank.description import *
-from migen.genlib.fsm import FSM, NextState
-
-
-class SPIMaster(Module, AutoCSR):
- def __init__(self, pads, width=24, div=2, cpha=1):
- self.pads = pads
-
- self._ctrl = CSR()
- self._length = CSRStorage(8)
- self._status = CSRStatus()
- if hasattr(pads, "mosi"):
- self._mosi = CSRStorage(width)
- if hasattr(pads, "miso"):
- self._miso = CSRStatus(width)
-
- self.irq = Signal()
-
- ###
-
- # ctrl
- start = Signal()
- length = self._length.storage
- enable_cs = Signal()
- enable_shift = Signal()
- done = Signal()
-
- self.comb += [
- start.eq(self._ctrl.re & self._ctrl.r[0]),
- self._status.status.eq(done)
- ]
-
- # clk
- i = Signal(max=div)
- clk_en = Signal()
- set_clk = Signal()
- clr_clk = Signal()
- self.sync += [
- If(set_clk,
- pads.clk.eq(enable_cs)
- ),
- If(clr_clk,
- pads.clk.eq(0),
- i.eq(0)
- ).Else(
- i.eq(i + 1),
- )
- ]
-
- self.comb += [
- set_clk.eq(i == (div//2-1)),
- clr_clk.eq(i == (div-1))
- ]
-
- # fsm
- cnt = Signal(8)
- 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",
- If(start,
- NextState("WAIT_CLK")
- ),
- done.eq(1),
- clr_cnt.eq(1)
- )
- fsm.act("WAIT_CLK",
- If(clr_clk,
- NextState("SHIFT")
- ),
- )
- fsm.act("SHIFT",
- If(cnt == length,
- NextState("END")
- ).Else(
- inc_cnt.eq(clr_clk),
- ),
- enable_cs.eq(1),
- enable_shift.eq(1),
- )
- fsm.act("END",
- If(set_clk,
- NextState("IDLE")
- ),
- enable_shift.eq(1),
- self.irq.eq(1)
- )
-
- # miso
- if hasattr(pads, "miso"):
- miso = Signal()
- sr_miso = Signal(width)
-
- # (cpha = 1: capture on clk falling edge)
- if cpha:
- self.sync += \
- If(enable_shift,
- If(clr_clk,
- miso.eq(pads.miso),
- ).Elif(set_clk,
- sr_miso.eq(Cat(miso, sr_miso[:-1]))
- )
- )
- # (cpha = 0: capture on clk rising edge)
- else:
- self.sync += \
- If(enable_shift,
- If(set_clk,
- miso.eq(pads.miso),
- ).Elif(clr_clk,
- sr_miso.eq(Cat(miso, sr_miso[:-1]))
- )
- )
- self.comb += self._miso.status.eq(sr_miso)
-
- # mosi
- if hasattr(pads, "mosi"):
- mosi = Signal()
- sr_mosi = Signal(width)
-
- # (cpha = 1: propagated on clk rising edge)
- if cpha:
- self.sync += \
- If(start,
- sr_mosi.eq(self._mosi.storage)
- ).Elif(clr_clk & enable_shift,
- sr_mosi.eq(Cat(Signal(), sr_mosi[:-1]))
- ).Elif(set_clk,
- pads.mosi.eq(sr_mosi[-1])
- )
-
- # (cpha = 0: propagated on clk falling edge)
- else:
- self.sync += [
- If(start,
- sr_mosi.eq(self._mosi.storage)
- ).Elif(set_clk & enable_shift,
- sr_mosi.eq(Cat(Signal(), sr_mosi[:-1]))
- ).Elif(clr_clk,
- pads.mosi.eq(sr_mosi[-1])
- )
- ]
-
- # cs_n
- self.comb += pads.cs_n.eq(~enable_cs)
+++ /dev/null
-from migen import *
-from migen.genlib.record import *
-from migen.sim.generic import run_simulation
-
-from misoc.com.spi import SPIMaster
-
-
-class SPISlave(Module):
- def __init__(self, pads, width):
- self.pads = pads
- self.width = width
-
- ###
-
- self.mosi = 0
- self.miso = 0
-
- self.last_cs_n = 1
- self.last_clk = 0
-
-
- def get_mosi(self):
- return self.mosi
-
- def set_miso(self, value):
- self.miso = value
-
- def do_simulation(self, selfp):
- # detect edges
- cs_n_rising = 0
- cs_n_falling = 0
- clk_rising = 0
- clk_falling = 0
- if selfp.pads.cs_n and not self.last_cs_n:
- cs_n_rising = 1
- if not selfp.pads.cs_n and self.last_cs_n:
- cs_n_falling = 1
- if selfp.pads.clk and not self.last_clk:
- clk_rising = 1
- if not selfp.pads.clk and self.last_clk:
- clk_falling = 1
-
- # input mosi
- if clk_falling and not selfp.pads.cs_n:
- self.mosi = self.mosi << 1
- self.mosi |= selfp.pads.mosi
-
- # output miso
- if (clk_rising and not selfp.pads.cs_n):
- selfp.pads.miso = (self.miso >> (self.width-1)) & 0x1
- self.miso = self.miso << 1
-
- # save signal states
- self.last_cs_n = selfp.pads.cs_n
- self.last_clk = selfp.pads.clk
-
-
-def spi_access(selfp, length, mosi):
- selfp.spi_master._mosi.storage = mosi
- yield
- selfp.spi_master._ctrl.r = (length << 8) | 1
- selfp.spi_master._ctrl.re = 1
- yield
- selfp.spi_master._ctrl.r = 0
- selfp.spi_master._ctrl.re = 0
- yield
- while not (selfp.spi_master._status.status & 0x1):
- yield
-
-
-class TB(Module):
- def __init__(self):
- pads = Record([("cs_n", 1), ("clk", 1), ("mosi", 1), ("miso", 1)])
- self.submodules.spi_master = SPIMaster(pads, 24, 4)
- self.submodules.spi_slave = SPISlave(pads, 24)
-
- def gen_simulation(self, selfp):
- for i in range(16):
- yield
- self.spi_slave.set_miso(0x123457)
- yield from spi_access(selfp, 8, 0x123457)
- print("{:08x}".format(self.spi_slave.get_mosi()))
- print("{:08x}".format(selfp.spi_master._miso.status))
-
-if __name__ == "__main__":
- run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True)
+++ /dev/null
-from migen import *
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-from migen.genlib.record import Record
-from migen.actorlib.fifo import SyncFIFO, AsyncFIFO
-
-
-def _get_uart_fifo(depth, sink_cd="sys", source_cd="sys"):
- if sink_cd != source_cd:
- fifo = AsyncFIFO([("data", 8)], depth)
- return ClockDomainsRenamer({"write": sink_cd, "read": source_cd})(fifo)
- else:
- return SyncFIFO([("data", 8)], depth)
-
-
-class UART(Module, AutoCSR):
- def __init__(self, phy,
- tx_fifo_depth=16,
- rx_fifo_depth=16,
- phy_cd="sys"):
- self._rxtx = CSR(8)
- self._txfull = CSRStatus()
- self._rxempty = CSRStatus()
-
- self.submodules.ev = EventManager()
- self.ev.tx = EventSourceProcess()
- self.ev.rx = EventSourceProcess()
- self.ev.finalize()
-
- # # #
-
- # TX
- tx_fifo = _get_uart_fifo(tx_fifo_depth, source_cd=phy_cd)
- self.submodules += tx_fifo
-
- self.comb += [
- tx_fifo.sink.stb.eq(self._rxtx.re),
- tx_fifo.sink.data.eq(self._rxtx.r),
- self._txfull.status.eq(~tx_fifo.sink.ack),
- Record.connect(tx_fifo.source, phy.sink),
- # Generate TX IRQ when tx_fifo becomes non-full
- self.ev.tx.trigger.eq(~tx_fifo.sink.ack)
- ]
-
-
- # RX
- rx_fifo = _get_uart_fifo(rx_fifo_depth, sink_cd=phy_cd)
- self.submodules += rx_fifo
-
-
- self.comb += [
- Record.connect(phy.source, rx_fifo.sink),
- self._rxempty.status.eq(~rx_fifo.source.stb),
- self._rxtx.w.eq(rx_fifo.source.data),
- rx_fifo.source.ack.eq(self.ev.rx.clear),
- # Generate RX IRQ when tx_fifo becomes non-empty
- self.ev.rx.trigger.eq(~rx_fifo.source.stb)
- ]
+++ /dev/null
-from migen import *
-
-from misoc.tools.wishbone import WishboneStreamingBridge
-from misoc.com.uart.phy.serial import UARTPHYSerial
-
-class UARTWishboneBridge(WishboneStreamingBridge):
- def __init__(self, pads, clk_freq, baudrate=115200):
- self.submodules.phy = UARTPHYSerial(pads, clk_freq, baudrate)
- WishboneStreamingBridge.__init__(self, self.phy, clk_freq)
+++ /dev/null
-def UARTPHY(pads, *args, **kwargs):
- # Autodetect PHY
- if hasattr(pads, "source_stb"):
- from misoc.com.uart.phy.sim import UARTPHYSim
- return UARTPHYSim(pads, *args, **kwargs)
- else:
- from misoc.com.uart.phy.serial import UARTPHYSerial
- return UARTPHYSerial(pads, *args, **kwargs)
+++ /dev/null
-from migen import *
-from migen.genlib.cdc import MultiReg
-from migen.bank.description import *
-from migen.flow.actor import Sink, Source
-
-
-class UARTPHYSerialRX(Module):
- def __init__(self, pads, tuning_word):
- self.source = Source([("data", 8)])
- ###
- uart_clk_rxen = Signal()
- phase_accumulator_rx = Signal(32)
-
- rx = Signal()
- self.specials += MultiReg(pads.rx, rx)
- rx_r = Signal()
- rx_reg = Signal(8)
- rx_bitcount = Signal(4)
- rx_busy = Signal()
- rx_done = self.source.stb
- rx_data = self.source.data
- self.sync += [
- rx_done.eq(0),
- rx_r.eq(rx),
- If(~rx_busy,
- If(~rx & rx_r, # look for start bit
- rx_busy.eq(1),
- rx_bitcount.eq(0),
- )
- ).Else(
- If(uart_clk_rxen,
- rx_bitcount.eq(rx_bitcount + 1),
- If(rx_bitcount == 0,
- If(rx, # verify start bit
- rx_busy.eq(0)
- )
- ).Elif(rx_bitcount == 9,
- rx_busy.eq(0),
- If(rx, # verify stop bit
- rx_data.eq(rx_reg),
- rx_done.eq(1)
- )
- ).Else(
- rx_reg.eq(Cat(rx_reg[1:], rx))
- )
- )
- )
- ]
- self.sync += \
- If(rx_busy,
- Cat(phase_accumulator_rx, uart_clk_rxen).eq(phase_accumulator_rx + tuning_word)
- ).Else(
- Cat(phase_accumulator_rx, uart_clk_rxen).eq(2**31)
- )
-
-
-class UARTPHYSerialTX(Module):
- def __init__(self, pads, tuning_word):
- self.sink = Sink([("data", 8)])
- ###
- uart_clk_txen = Signal()
- phase_accumulator_tx = Signal(32)
-
- pads.tx.reset = 1
-
- tx_reg = Signal(8)
- tx_bitcount = Signal(4)
- tx_busy = Signal()
- self.sync += [
- self.sink.ack.eq(0),
- If(self.sink.stb & ~tx_busy & ~self.sink.ack,
- tx_reg.eq(self.sink.data),
- tx_bitcount.eq(0),
- tx_busy.eq(1),
- pads.tx.eq(0)
- ).Elif(uart_clk_txen & tx_busy,
- tx_bitcount.eq(tx_bitcount + 1),
- If(tx_bitcount == 8,
- pads.tx.eq(1)
- ).Elif(tx_bitcount == 9,
- pads.tx.eq(1),
- tx_busy.eq(0),
- self.sink.ack.eq(1),
- ).Else(
- pads.tx.eq(tx_reg[0]),
- tx_reg.eq(Cat(tx_reg[1:], 0))
- )
- )
- ]
- self.sync += [
- If(tx_busy,
- Cat(phase_accumulator_tx, uart_clk_txen).eq(phase_accumulator_tx + tuning_word)
- ).Else(
- Cat(phase_accumulator_tx, uart_clk_txen).eq(0)
- )
- ]
-
-
-class UARTPHYSerial(Module, AutoCSR):
- def __init__(self, pads, clk_freq, baudrate=115200):
- self._tuning_word = CSRStorage(32, reset=int((baudrate/clk_freq)*2**32))
- self.submodules.tx = UARTPHYSerialTX(pads, self._tuning_word.storage)
- self.submodules.rx = UARTPHYSerialRX(pads, self._tuning_word.storage)
- self.sink, self.source = self.tx.sink, self.rx.source
+++ /dev/null
-import os
-import pty
-import time
-
-from migen import *
-from migen.flow.actor import Sink, Source
-
-
-class UARTPHYSim(Module):
- def __init__(self, pads, *args, **kwargs):
- self.sink = Sink([("data", 8)])
- self.source = Source([("data", 8)])
-
- self.comb += [
- pads.source_stb.eq(self.sink.stb),
- pads.source_data.eq(self.sink.data),
- self.sink.ack.eq(pads.source_ack),
-
- self.source.stb.eq(pads.sink_stb),
- self.source.data.eq(pads.sink_data),
- pads.sink_ack.eq(self.source.ack)
- ]
-
- m, s = pty.openpty()
- name = os.ttyname(s)
- print("UART tty: "+name)
- time.sleep(0.5) # pause for user
- f = open("/tmp/simserial", "w")
- f.write(os.ttyname(s))
- f.close()
-
- def do_exit(self, *args, **kwargs):
- os.remove("/tmp/simserial")
+++ /dev/null
-import csv
-
-
-class MappedReg:
- def __init__(self, readfn, writefn, name, addr, length, busword, mode):
- self.readfn = readfn
- self.writefn = writefn
- self.addr = addr
- self.length = length
- self.busword = busword
- self.mode = mode
-
- def read(self):
- if self.mode not in ["rw", "ro"]:
- raise KeyError(name + "register not readable")
- datas = self.readfn(self.addr, burst_length=self.length)
- if isinstance(datas, int):
- return datas
- else:
- data = 0
- for i in range(self.length):
- data = data << self.busword
- data |= datas[i]
- return data
-
- def write(self, value):
- if self.mode not in ["rw", "wo"]:
- raise KeyError(name + "register not writable")
- datas = []
- for i in range(self.length):
- datas.append((value >> ((self.length-1-i)*self.busword)) & (2**self.busword-1))
- self.writefn(self.addr, datas)
-
-
-class MappedRegs:
- def __init__(self, d):
- self.d = d
-
- def __getattr__(self, attr):
- try:
- return self.__dict__['d'][attr]
- except KeyError:
- pass
- raise KeyError("No such register " + attr)
-
-
-def build_map(addrmap, busword, readfn, writefn):
- csv_reader = csv.reader(open(addrmap), delimiter=',', quotechar='#')
- d = {}
- for item in csv_reader:
- name, addr, length, mode = item
- addr = int(addr.replace("0x", ""), 16)
- length = int(length)
- d[name] = MappedReg(readfn, writefn, name, addr, length, busword, mode)
- return MappedRegs(d)
+++ /dev/null
-import serial
-from struct import *
-from misoc.com.uart.software.reg import *
-
-
-def write_b(uart, data):
- uart.write(pack('B', data))
-
-
-class UARTWishboneBridgeDriver:
- cmds = {
- "write": 0x01,
- "read": 0x02
- }
- def __init__(self, port, baudrate=115200, addrmap=None, busword=8, debug=False):
- self.port = port
- self.baudrate = str(baudrate)
- self.debug = debug
- self.uart = serial.Serial(port, baudrate, timeout=0.25)
- if addrmap is not None:
- self.regs = build_map(addrmap, busword, self.read, self.write)
-
- def open(self):
- self.uart.flushOutput()
- self.uart.close()
- self.uart.open()
- self.uart.flushInput()
-
- def close(self):
- self.uart.flushOutput()
- self.uart.close()
-
- def read(self, addr, burst_length=1):
- datas = []
- self.uart.flushInput()
- write_b(self.uart, self.cmds["read"])
- write_b(self.uart, burst_length)
- word_addr = addr//4
- write_b(self.uart, (word_addr >> 24) & 0xff)
- write_b(self.uart, (word_addr >> 16) & 0xff)
- write_b(self.uart, (word_addr >> 8) & 0xff)
- write_b(self.uart, (word_addr >> 0) & 0xff)
- for i in range(burst_length):
- data = 0
- for k in range(4):
- data = data << 8
- data |= ord(self.uart.read())
- if self.debug:
- print("RD {:08X} @ {:08X}".format(data, addr + 4*i))
- datas.append(data)
- if burst_length == 1:
- return datas[0]
- else:
- return datas
-
- def write(self, addr, data):
- if isinstance(data, list):
- burst_length = len(data)
- else:
- burst_length = 1
- data = [data]
- write_b(self.uart, self.cmds["write"])
- write_b(self.uart, burst_length)
- word_addr = addr//4
- write_b(self.uart, (word_addr >> 24) & 0xff)
- write_b(self.uart, (word_addr >> 16) & 0xff)
- write_b(self.uart, (word_addr >> 8) & 0xff)
- write_b(self.uart, (word_addr >> 0) & 0xff)
- for i in range(len(data)):
- dat = data[i]
- for j in range(4):
- write_b(self.uart, (dat >> 24) & 0xff)
- dat = dat << 8
- if self.debug:
- print("WR {:08X} @ {:08X}".format(data[i], addr + 4*i))
+++ /dev/null
-# XXX Adapt test to new architecture
-class UARTTB(Module):
- def __init__(self):
- self.clk_freq = 83333333
- self.baud = 3000000
- self.pads = Record([("rx", 1), ("tx", 1)])
- self.submodules.slave = UART(self.pads, self.clk_freq, self.baud)
-
- def wait_for(self, ns_time):
- freq_in_ghz = self.clk_freq/(10**9)
- period = 1/freq_in_ghz
- num_loops = int(ns_time/period)
- for i in range(num_loops+1):
- yield
-
- def gen_simulation(self, selfp):
- baud_in_ghz = self.baud/(10**9)
- uart_period = int(1/baud_in_ghz)
- half_uart_period = int(1/(2*baud_in_ghz))
-
- # Set TX an RX lines idle
- selfp.pads.tx = 1
- selfp.pads.rx = 1
- yield
-
- # First send a few characters
-
- tx_string = "01234"
- print("Sending string: " + tx_string)
- for c in tx_string:
- selfp.slave._r_rxtx.r = ord(c)
- selfp.slave._r_rxtx.re = 1
- yield
- selfp.slave._r_rxtx.re = 0
-
- yield from self.wait_for(half_uart_period)
-
- if selfp.pads.tx:
- print("FAILURE: no start bit sent")
-
- val = 0
- for i in range(8):
- yield from self.wait_for(uart_period)
- val >>= 1
- if selfp.pads.tx:
- val |= 0x80
-
- yield from self.wait_for(uart_period)
-
- if selfp.pads.tx == 0:
- print("FAILURE: no stop bit sent")
-
- if ord(c) != val:
- print("FAILURE: sent decimal value "+str(val)+" (char "+chr(val)+") instead of "+c)
- else:
- print("SUCCESS: sent "+c)
- while selfp.slave.ev.tx.trigger != 1:
- yield
-
- # Then receive a character
-
- rx_string = '5'
- print("Receiving character "+rx_string)
- rx_value = ord(rx_string)
- for i in range(11):
- if (i == 0):
- # start bit
- selfp.pads.rx = 0
- elif (i == 9):
- # stop bit
- selfp.pads.rx = 1
- elif (i == 10):
- selfp.pads.rx = 1
- break
- else:
- selfp.pads.rx = 1 if (rx_value & 1) else 0
- rx_value >>= 1
- yield from self.wait_for(uart_period)
-
- rx_value = ord(rx_string)
- received_value = selfp.slave._r_rxtx.w
- if (received_value == rx_value):
- print("RX SUCCESS: ")
- else:
- print("RX FAILURE: ")
-
- print("received "+chr(received_value))
-
- while True:
- yield
-
-if __name__ == "__main__":
- from migen.sim.generic import Simulator, TopLevel
- from migen.sim import icarus
- with Simulator(UARTTB(), TopLevel("top.vcd", clk_period=int(1/0.08333333)),
- icarus.Runner(keep_files=False)) as s:
- s.run(20000)
+++ /dev/null
-import subprocess
-
-from migen import *
-from migen.bank.description import *
-
-def get_id():
- output = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii")
- return int(output[:8], 16)
-
-
-class Identifier(Module, AutoCSR):
- def __init__(self, sysid, frequency, revision=None):
- self._sysid = CSRStatus(16)
- self._revision = CSRStatus(32)
- self._frequency = CSRStatus(32)
-
- ###
-
- if revision is None:
- revision = get_id()
-
- self.comb += [
- self._sysid.status.eq(sysid),
- self._revision.status.eq(revision),
- self._frequency.status.eq(frequency)
- ]
+++ /dev/null
-import os
-
-from migen import *
-from migen.bus import wishbone
-
-
-class LM32(Module):
- def __init__(self, platform, eba_reset):
- self.ibus = i = wishbone.Interface()
- self.dbus = d = wishbone.Interface()
- self.interrupt = Signal(32)
-
- ###
-
- i_adr_o = Signal(32)
- d_adr_o = Signal(32)
- self.specials += Instance("lm32_cpu",
- p_eba_reset=Instance.PreformattedParam("32'h{:08x}".format(eba_reset)),
-
- i_clk_i=ClockSignal(),
- i_rst_i=ResetSignal(),
-
- i_interrupt=self.interrupt,
-
- o_I_ADR_O=i_adr_o,
- o_I_DAT_O=i.dat_w,
- o_I_SEL_O=i.sel,
- o_I_CYC_O=i.cyc,
- o_I_STB_O=i.stb,
- o_I_WE_O=i.we,
- o_I_CTI_O=i.cti,
- o_I_BTE_O=i.bte,
- i_I_DAT_I=i.dat_r,
- i_I_ACK_I=i.ack,
- i_I_ERR_I=i.err,
- i_I_RTY_I=0,
-
- o_D_ADR_O=d_adr_o,
- o_D_DAT_O=d.dat_w,
- o_D_SEL_O=d.sel,
- o_D_CYC_O=d.cyc,
- o_D_STB_O=d.stb,
- o_D_WE_O=d.we,
- o_D_CTI_O=d.cti,
- o_D_BTE_O=d.bte,
- i_D_DAT_I=d.dat_r,
- i_D_ACK_I=d.ack,
- i_D_ERR_I=d.err,
- i_D_RTY_I=0)
-
- self.comb += [
- self.ibus.adr.eq(i_adr_o[2:]),
- self.dbus.adr.eq(d_adr_o[2:])
- ]
-
- # add Verilog sources
- platform.add_sources(os.path.join("extcores", "lm32", "submodule", "rtl"),
- "lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v",
- "lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v",
- "lm32_shifter.v", "lm32_multiplier.v", "lm32_mc_arithmetic.v",
- "lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v",
- "lm32_dcache.v", "lm32_debug.v", "lm32_itlb.v", "lm32_dtlb.v")
- platform.add_verilog_include_path(os.path.join("extcores", "lm32"))
+++ /dev/null
-import os
-
-from migen import *
-from migen.bus import wishbone
-
-
-class MOR1KX(Module):
- def __init__(self, platform, reset_pc):
- self.ibus = i = wishbone.Interface()
- self.dbus = d = wishbone.Interface()
- self.interrupt = Signal(32)
-
- ###
-
- i_adr_o = Signal(32)
- d_adr_o = Signal(32)
- self.specials += Instance("mor1kx",
- p_FEATURE_INSTRUCTIONCACHE="ENABLED",
- p_OPTION_ICACHE_BLOCK_WIDTH=4,
- p_OPTION_ICACHE_SET_WIDTH=8,
- p_OPTION_ICACHE_WAYS=1,
- p_OPTION_ICACHE_LIMIT_WIDTH=31,
- p_FEATURE_DATACACHE="ENABLED",
- p_OPTION_DCACHE_BLOCK_WIDTH=4,
- p_OPTION_DCACHE_SET_WIDTH=8,
- p_OPTION_DCACHE_WAYS=1,
- p_OPTION_DCACHE_LIMIT_WIDTH=31,
- p_FEATURE_TIMER="NONE",
- p_OPTION_PIC_TRIGGER="LEVEL",
- p_FEATURE_SYSCALL="NONE",
- p_FEATURE_TRAP="NONE",
- p_FEATURE_RANGE="NONE",
- p_FEATURE_OVERFLOW="NONE",
- p_FEATURE_ADDC="ENABLED",
- p_FEATURE_CMOV="ENABLED",
- p_FEATURE_FFL1="ENABLED",
- p_OPTION_CPU0="CAPPUCCINO",
- p_OPTION_RESET_PC=reset_pc,
- p_IBUS_WB_TYPE="B3_REGISTERED_FEEDBACK",
- p_DBUS_WB_TYPE="B3_REGISTERED_FEEDBACK",
-
- i_clk=ClockSignal(),
- i_rst=ResetSignal(),
-
- i_irq_i=self.interrupt,
-
- o_iwbm_adr_o=i_adr_o,
- o_iwbm_dat_o=i.dat_w,
- o_iwbm_sel_o=i.sel,
- o_iwbm_cyc_o=i.cyc,
- o_iwbm_stb_o=i.stb,
- o_iwbm_we_o=i.we,
- o_iwbm_cti_o=i.cti,
- o_iwbm_bte_o=i.bte,
- i_iwbm_dat_i=i.dat_r,
- i_iwbm_ack_i=i.ack,
- i_iwbm_err_i=i.err,
- i_iwbm_rty_i=0,
-
- o_dwbm_adr_o=d_adr_o,
- o_dwbm_dat_o=d.dat_w,
- o_dwbm_sel_o=d.sel,
- o_dwbm_cyc_o=d.cyc,
- o_dwbm_stb_o=d.stb,
- o_dwbm_we_o=d.we,
- o_dwbm_cti_o=d.cti,
- o_dwbm_bte_o=d.bte,
- i_dwbm_dat_i=d.dat_r,
- i_dwbm_ack_i=d.ack,
- i_dwbm_err_i=d.err,
- i_dwbm_rty_i=0)
-
- self.comb += [
- self.ibus.adr.eq(i_adr_o[2:]),
- self.dbus.adr.eq(d_adr_o[2:])
- ]
-
- # add Verilog sources
- platform.add_source_dir(os.path.join("extcores", "mor1kx", "submodule",
- "rtl", "verilog"))
+++ /dev/null
-from migen import *
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-
-
-class Timer(Module, AutoCSR):
- def __init__(self, width=32):
- self._load = CSRStorage(width)
- self._reload = CSRStorage(width)
- self._en = CSRStorage()
- self._update_value = CSR()
- self._value = CSRStatus(width)
-
- self.submodules.ev = EventManager()
- self.ev.zero = EventSourceProcess()
- self.ev.finalize()
-
- ###
-
- value = Signal(width)
- self.sync += [
- If(self._en.storage,
- If(value == 0,
- # set reload to 0 to disable reloading
- value.eq(self._reload.storage)
- ).Else(
- value.eq(value - 1)
- )
- ).Else(
- value.eq(self._load.storage)
- ),
- If(self._update_value.re, self._value.status.eq(value))
- ]
- self.comb += self.ev.zero.trigger.eq(value != 0)
--- /dev/null
+from misoc.dvisampler.core import DVISampler
--- /dev/null
+from migen import *
+from migen.genlib.cdc import MultiReg, PulseSynchronizer
+from migen.genlib.fifo import AsyncFIFO
+from migen.genlib.record import Record
+from migen.bank.description import *
+from migen.flow.actor import *
+
+from misoc.dvisampler.common import channel_layout
+
+
+class SyncPolarity(Module):
+ def __init__(self):
+ self.valid_i = Signal()
+ self.data_in0 = Record(channel_layout)
+ self.data_in1 = Record(channel_layout)
+ self.data_in2 = Record(channel_layout)
+
+ self.valid_o = Signal()
+ self.de = Signal()
+ self.hsync = Signal()
+ self.vsync = Signal()
+ self.r = Signal(8)
+ self.g = Signal(8)
+ self.b = Signal(8)
+
+ ###
+
+ de = self.data_in0.de
+ de_r = Signal()
+ c = self.data_in0.c
+ c_polarity = Signal(2)
+ c_out = Signal(2)
+
+ self.comb += [
+ self.de.eq(de_r),
+ self.hsync.eq(c_out[0]),
+ self.vsync.eq(c_out[1])
+ ]
+
+ self.sync.pix += [
+ self.valid_o.eq(self.valid_i),
+ self.r.eq(self.data_in2.d),
+ self.g.eq(self.data_in1.d),
+ self.b.eq(self.data_in0.d),
+
+ de_r.eq(de),
+ If(de_r & ~de,
+ c_polarity.eq(c),
+ c_out.eq(0)
+ ).Else(
+ c_out.eq(c ^ c_polarity)
+ )
+ ]
+
+
+class ResolutionDetection(Module, AutoCSR):
+ def __init__(self, nbits=11):
+ self.valid_i = Signal()
+ self.vsync = Signal()
+ self.de = Signal()
+
+ self._hres = CSRStatus(nbits)
+ self._vres = CSRStatus(nbits)
+
+ ###
+
+ # Detect DE transitions
+ de_r = Signal()
+ pn_de = Signal()
+ self.sync.pix += de_r.eq(self.de)
+ self.comb += pn_de.eq(~self.de & de_r)
+
+ # HRES
+ hcounter = Signal(nbits)
+ self.sync.pix += If(self.valid_i & self.de,
+ hcounter.eq(hcounter + 1)
+ ).Else(
+ hcounter.eq(0)
+ )
+
+ hcounter_st = Signal(nbits)
+ self.sync.pix += If(self.valid_i,
+ If(pn_de, hcounter_st.eq(hcounter))
+ ).Else(
+ hcounter_st.eq(0)
+ )
+ self.specials += MultiReg(hcounter_st, self._hres.status)
+
+ # VRES
+ vsync_r = Signal()
+ p_vsync = Signal()
+ self.sync.pix += vsync_r.eq(self.vsync),
+ self.comb += p_vsync.eq(self.vsync & ~vsync_r)
+
+ vcounter = Signal(nbits)
+ self.sync.pix += If(self.valid_i & p_vsync,
+ vcounter.eq(0)
+ ).Elif(pn_de,
+ vcounter.eq(vcounter + 1)
+ )
+
+ vcounter_st = Signal(nbits)
+ self.sync.pix += If(self.valid_i,
+ If(p_vsync, vcounter_st.eq(vcounter))
+ ).Else(
+ vcounter_st.eq(0)
+ )
+ self.specials += MultiReg(vcounter_st, self._vres.status)
+
+
+class FrameExtraction(Module, AutoCSR):
+ def __init__(self, word_width, fifo_depth):
+ # in pix clock domain
+ self.valid_i = Signal()
+ self.vsync = Signal()
+ self.de = Signal()
+ self.r = Signal(8)
+ self.g = Signal(8)
+ self.b = Signal(8)
+
+ # in sys clock domain
+ word_layout = [("sof", 1), ("pixels", word_width)]
+ self.frame = Source(word_layout)
+ self.busy = Signal()
+
+ self._overflow = CSR()
+
+ ###
+
+ # start of frame detection
+ vsync_r = Signal()
+ new_frame = Signal()
+ self.comb += new_frame.eq(self.vsync & ~vsync_r)
+ self.sync.pix += vsync_r.eq(self.vsync)
+
+ # pack pixels into words
+ cur_word = Signal(word_width)
+ cur_word_valid = Signal()
+ encoded_pixel = Signal(24)
+ self.comb += encoded_pixel.eq(Cat(self.b, self.g, self.r))
+ pack_factor = word_width//24
+ assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
+ pack_counter = Signal(max=pack_factor)
+ self.sync.pix += [
+ cur_word_valid.eq(0),
+ If(new_frame,
+ cur_word_valid.eq(pack_counter == (pack_factor - 1)),
+ pack_counter.eq(0),
+ ).Elif(self.valid_i & self.de,
+ [If(pack_counter == (pack_factor-i-1),
+ cur_word[24*i:24*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)],
+ cur_word_valid.eq(pack_counter == (pack_factor - 1)),
+ pack_counter.eq(pack_counter + 1)
+ )
+ ]
+
+ # FIFO
+ fifo = RenameClockDomains(AsyncFIFO(word_layout, fifo_depth),
+ {"write": "pix", "read": "sys"})
+ self.submodules += fifo
+ self.comb += [
+ fifo.din.pixels.eq(cur_word),
+ fifo.we.eq(cur_word_valid)
+ ]
+ self.sync.pix += \
+ If(new_frame,
+ fifo.din.sof.eq(1)
+ ).Elif(cur_word_valid,
+ fifo.din.sof.eq(0)
+ )
+ self.comb += [
+ self.frame.stb.eq(fifo.readable),
+ self.frame.payload.eq(fifo.dout),
+ fifo.re.eq(self.frame.ack),
+ self.busy.eq(0)
+ ]
+
+ # overflow detection
+ pix_overflow = Signal()
+ pix_overflow_reset = Signal()
+ self.sync.pix += [
+ If(fifo.we & ~fifo.writable,
+ pix_overflow.eq(1)
+ ).Elif(pix_overflow_reset,
+ pix_overflow.eq(0)
+ )
+ ]
+
+ sys_overflow = Signal()
+ self.specials += MultiReg(pix_overflow, sys_overflow)
+ self.submodules.overflow_reset = PulseSynchronizer("sys", "pix")
+ self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys")
+ self.comb += [
+ pix_overflow_reset.eq(self.overflow_reset.o),
+ self.overflow_reset_ack.i.eq(pix_overflow_reset)
+ ]
+
+ overflow_mask = Signal()
+ self.comb += [
+ self._overflow.w.eq(sys_overflow & ~overflow_mask),
+ self.overflow_reset.i.eq(self._overflow.re)
+ ]
+ self.sync += \
+ If(self._overflow.re,
+ overflow_mask.eq(1)
+ ).Elif(self.overflow_reset_ack.o,
+ overflow_mask.eq(0)
+ )
--- /dev/null
+from migen import *
+from migen.genlib.cdc import MultiReg
+from migen.genlib.fifo import _inc
+from migen.genlib.record import Record, layout_len
+from migen.genlib.misc import optree
+from migen.bank.description import *
+
+from misoc.dvisampler.common import channel_layout
+
+
+class _SyncBuffer(Module):
+ def __init__(self, width, depth):
+ self.din = Signal(width)
+ self.dout = Signal(width)
+ self.re = Signal()
+
+ ###
+
+ produce = Signal(max=depth)
+ consume = Signal(max=depth)
+ storage = Memory(width, depth)
+ self.specials += storage
+
+ wrport = storage.get_port(write_capable=True)
+ self.specials += wrport
+ self.comb += [
+ wrport.adr.eq(produce),
+ wrport.dat_w.eq(self.din),
+ wrport.we.eq(1)
+ ]
+ self.sync += _inc(produce, depth)
+
+ rdport = storage.get_port(async_read=True)
+ self.specials += rdport
+ self.comb += [
+ rdport.adr.eq(consume),
+ self.dout.eq(rdport.dat_r)
+ ]
+ self.sync += If(self.re, _inc(consume, depth))
+
+
+class ChanSync(Module, AutoCSR):
+ def __init__(self, nchan=3, depth=8):
+ self.valid_i = Signal()
+ self.chan_synced = Signal()
+
+ self._channels_synced = CSRStatus()
+
+ lst_control = []
+ all_control = Signal()
+ for i in range(nchan):
+ name = "data_in" + str(i)
+ data_in = Record(channel_layout, name=name)
+ setattr(self, name, data_in)
+ name = "data_out" + str(i)
+ data_out = Record(channel_layout, name=name)
+ setattr(self, name, data_out)
+
+ ###
+
+ syncbuffer = RenameClockDomains(_SyncBuffer(layout_len(channel_layout), depth), "pix")
+ self.submodules += syncbuffer
+ self.comb += [
+ syncbuffer.din.eq(data_in.raw_bits()),
+ data_out.raw_bits().eq(syncbuffer.dout)
+ ]
+ is_control = Signal()
+ self.comb += [
+ is_control.eq(~data_out.de),
+ syncbuffer.re.eq(~is_control | all_control)
+ ]
+ lst_control.append(is_control)
+
+ some_control = Signal()
+ self.comb += [
+ all_control.eq(optree("&", lst_control)),
+ some_control.eq(optree("|", lst_control))
+ ]
+ self.sync.pix += If(~self.valid_i,
+ self.chan_synced.eq(0)
+ ).Else(
+ If(some_control,
+ If(all_control,
+ self.chan_synced.eq(1)
+ ).Else(
+ self.chan_synced.eq(0)
+ )
+ )
+ )
+ self.specials += MultiReg(self.chan_synced, self._channels_synced.status)
+
+
+class _TB(Module):
+ def __init__(self, test_seq_it):
+ self.test_seq_it = test_seq_it
+
+ self.submodules.chansync = RenameClockDomains(ChanSync(), {"pix": "sys"})
+ self.comb += self.chansync.valid_i.eq(1)
+
+ def do_simulation(self, selfp):
+ try:
+ de0, de1, de2 = next(self.test_seq_it)
+ except StopIteration:
+ raise StopSimulation
+
+ selfp.chansync.data_in0.de = de0
+ selfp.chansync.data_in1.de = de1
+ selfp.chansync.data_in2.de = de2
+ selfp.chansync.data_in0.d = selfp.simulator.cycle_counter
+ selfp.chansync.data_in1.d = selfp.simulator.cycle_counter
+ selfp.chansync.data_in2.d = selfp.simulator.cycle_counter
+
+ out0 = selfp.chansync.data_out0.d
+ out1 = selfp.chansync.data_out1.d
+ out2 = selfp.chansync.data_out2.d
+
+ print("{0:5} {1:5} {2:5}".format(out0, out1, out2))
+
+if __name__ == "__main__":
+ from migen.sim.generic import run_simulation
+
+ test_seq = [
+ (1, 1, 1),
+ (1, 1, 0),
+ (0, 0, 0),
+ (0, 0, 0),
+ (0, 0, 1),
+ (1, 1, 1),
+ (1, 1, 1),
+ ]
+ tb = _TB(iter(test_seq*2))
+ run_simulation(tb)
--- /dev/null
+from migen import *
+from migen.genlib.cdc import MultiReg
+from migen.genlib.misc import optree
+from migen.bank.description import *
+
+from misoc.dvisampler.common import control_tokens
+
+
+class CharSync(Module, AutoCSR):
+ def __init__(self, required_controls=8):
+ self.raw_data = Signal(10)
+ self.synced = Signal()
+ self.data = Signal(10)
+
+ self._char_synced = CSRStatus()
+ self._ctl_pos = CSRStatus(bits_for(9))
+
+ ###
+
+ raw_data1 = Signal(10)
+ self.sync.pix += raw_data1.eq(self.raw_data)
+ raw = Signal(20)
+ self.comb += raw.eq(Cat(raw_data1, self.raw_data))
+
+ found_control = Signal()
+ control_position = Signal(max=10)
+ self.sync.pix += found_control.eq(0)
+ for i in range(10):
+ self.sync.pix += If(optree("|", [raw[i:i+10] == t for t in control_tokens]),
+ found_control.eq(1),
+ control_position.eq(i)
+ )
+
+ control_counter = Signal(max=required_controls)
+ previous_control_position = Signal(max=10)
+ word_sel = Signal(max=10)
+ self.sync.pix += [
+ If(found_control & (control_position == previous_control_position),
+ If(control_counter == (required_controls - 1),
+ control_counter.eq(0),
+ self.synced.eq(1),
+ word_sel.eq(control_position)
+ ).Else(
+ control_counter.eq(control_counter + 1)
+ )
+ ).Else(
+ control_counter.eq(0)
+ ),
+ previous_control_position.eq(control_position)
+ ]
+ self.specials += MultiReg(self.synced, self._char_synced.status)
+ self.specials += MultiReg(word_sel, self._ctl_pos.status)
+
+ self.sync.pix += self.data.eq(raw >> word_sel)
--- /dev/null
+from migen import *
+from migen.genlib.cdc import MultiReg
+from migen.bank.description import *
+
+
+class Clocking(Module, AutoCSR):
+ def __init__(self, pads):
+ self._pll_reset = CSRStorage(reset=1)
+ self._locked = CSRStatus()
+
+ # DRP
+ self._pll_adr = CSRStorage(5)
+ self._pll_dat_r = CSRStatus(16)
+ self._pll_dat_w = CSRStorage(16)
+ self._pll_read = CSR()
+ self._pll_write = CSR()
+ self._pll_drdy = CSRStatus()
+
+ self.locked = Signal()
+ self.serdesstrobe = Signal()
+ self.clock_domains._cd_pix = ClockDomain()
+ self.clock_domains._cd_pix2x = ClockDomain()
+ self.clock_domains._cd_pix10x = ClockDomain(reset_less=True)
+
+ ###
+
+ clk_se = Signal()
+ self.specials += Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_se)
+
+ clkfbout = Signal()
+ pll_locked = Signal()
+ pll_clk0 = Signal()
+ pll_clk1 = Signal()
+ pll_clk2 = Signal()
+ pll_drdy = Signal()
+ self.sync += If(self._pll_read.re | self._pll_write.re,
+ self._pll_drdy.status.eq(0)
+ ).Elif(pll_drdy,
+ self._pll_drdy.status.eq(1)
+ )
+ self.specials += Instance("PLL_ADV",
+ p_CLKFBOUT_MULT=10,
+ p_CLKOUT0_DIVIDE=1, # pix10x
+ p_CLKOUT1_DIVIDE=5, # pix2x
+ p_CLKOUT2_DIVIDE=10, # pix
+ p_COMPENSATION="INTERNAL",
+
+ i_CLKINSEL=1,
+ i_CLKIN1=clk_se,
+ o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
+ o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
+ o_LOCKED=pll_locked, i_RST=self._pll_reset.storage,
+
+ i_DADDR=self._pll_adr.storage,
+ o_DO=self._pll_dat_r.status,
+ i_DI=self._pll_dat_w.storage,
+ i_DEN=self._pll_read.re | self._pll_write.re,
+ i_DWE=self._pll_write.re,
+ o_DRDY=pll_drdy,
+ i_DCLK=ClockSignal())
+
+ locked_async = Signal()
+ self.specials += [
+ Instance("BUFPLL", p_DIVIDE=5,
+ i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked,
+ o_IOCLK=self._cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
+ Instance("BUFG", i_I=pll_clk1, o_O=self._cd_pix2x.clk),
+ Instance("BUFG", i_I=pll_clk2, o_O=self._cd_pix.clk),
+ MultiReg(locked_async, self.locked, "sys")
+ ]
+ self.comb += self._locked.status.eq(self.locked)
+
+ # sychronize pix+pix2x reset
+ pix_rst_n = 1
+ for i in range(2):
+ new_pix_rst_n = Signal()
+ self.specials += Instance("FDCE", i_D=pix_rst_n, i_CE=1, i_C=ClockSignal("pix"),
+ i_CLR=~locked_async, o_Q=new_pix_rst_n)
+ pix_rst_n = new_pix_rst_n
+ self.comb += self._cd_pix.rst.eq(~pix_rst_n), self._cd_pix2x.rst.eq(~pix_rst_n)
--- /dev/null
+control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
+channel_layout = [("d", 8), ("c", 2), ("de", 1)]
--- /dev/null
+from migen import *
+from migen.bank.description import AutoCSR
+
+from misoc.dvisampler.edid import EDID
+from misoc.dvisampler.clocking import Clocking
+from misoc.dvisampler.datacapture import DataCapture
+from misoc.dvisampler.charsync import CharSync
+from misoc.dvisampler.wer import WER
+from misoc.dvisampler.decoding import Decoding
+from misoc.dvisampler.chansync import ChanSync
+from misoc.dvisampler.analysis import SyncPolarity, ResolutionDetection, FrameExtraction
+from misoc.dvisampler.dma import DMA
+
+
+class DVISampler(Module, AutoCSR):
+ def __init__(self, pads, lasmim, n_dma_slots=2, fifo_depth=512):
+ self.submodules.edid = EDID(pads)
+ self.submodules.clocking = Clocking(pads)
+
+ for datan in range(3):
+ name = "data" + str(datan)
+
+ cap = DataCapture(getattr(pads, name + "_p"), getattr(pads, name + "_n"), 8)
+ setattr(self.submodules, name + "_cap", cap)
+ self.comb += cap.serdesstrobe.eq(self.clocking.serdesstrobe)
+
+ charsync = CharSync()
+ setattr(self.submodules, name + "_charsync", charsync)
+ self.comb += charsync.raw_data.eq(cap.d)
+
+ wer = WER()
+ setattr(self.submodules, name + "_wer", wer)
+ self.comb += wer.data.eq(charsync.data)
+
+ decoding = Decoding()
+ setattr(self.submodules, name + "_decod", decoding)
+ self.comb += [
+ decoding.valid_i.eq(charsync.synced),
+ decoding.input.eq(charsync.data)
+ ]
+
+ self.submodules.chansync = ChanSync()
+ self.comb += [
+ self.chansync.valid_i.eq(self.data0_decod.valid_o & \
+ self.data1_decod.valid_o & self.data2_decod.valid_o),
+ self.chansync.data_in0.eq(self.data0_decod.output),
+ self.chansync.data_in1.eq(self.data1_decod.output),
+ self.chansync.data_in2.eq(self.data2_decod.output),
+ ]
+
+ self.submodules.syncpol = SyncPolarity()
+ self.comb += [
+ self.syncpol.valid_i.eq(self.chansync.chan_synced),
+ self.syncpol.data_in0.eq(self.chansync.data_out0),
+ self.syncpol.data_in1.eq(self.chansync.data_out1),
+ self.syncpol.data_in2.eq(self.chansync.data_out2)
+ ]
+
+ self.submodules.resdetection = ResolutionDetection()
+ self.comb += [
+ self.resdetection.valid_i.eq(self.syncpol.valid_o),
+ self.resdetection.de.eq(self.syncpol.de),
+ self.resdetection.vsync.eq(self.syncpol.vsync)
+ ]
+
+ self.submodules.frame = FrameExtraction(24*lasmim.dw//32, fifo_depth)
+ self.comb += [
+ self.frame.valid_i.eq(self.syncpol.valid_o),
+ self.frame.de.eq(self.syncpol.de),
+ self.frame.vsync.eq(self.syncpol.vsync),
+ self.frame.r.eq(self.syncpol.r),
+ self.frame.g.eq(self.syncpol.g),
+ self.frame.b.eq(self.syncpol.b)
+ ]
+
+ self.submodules.dma = DMA(lasmim, n_dma_slots)
+ self.comb += self.frame.frame.connect(self.dma.frame)
+ self.ev = self.dma.ev
+
+ autocsr_exclude = {"ev"}
--- /dev/null
+from migen import *
+from migen.genlib.cdc import MultiReg, PulseSynchronizer
+from migen.bank.description import *
+
+
+class DataCapture(Module, AutoCSR):
+ def __init__(self, pad_p, pad_n, ntbits):
+ self.serdesstrobe = Signal()
+ self.d = Signal(10)
+
+ self._dly_ctl = CSR(6)
+ self._dly_busy = CSRStatus(2)
+ self._phase = CSRStatus(2)
+ self._phase_reset = CSR()
+
+ ###
+
+ # IO
+ pad_se = Signal()
+ self.specials += Instance("IBUFDS", i_I=pad_p, i_IB=pad_n, o_O=pad_se)
+
+ pad_delayed_master = Signal()
+ pad_delayed_slave = Signal()
+ delay_inc = Signal()
+ delay_ce = Signal()
+ delay_master_cal = Signal()
+ delay_master_rst = Signal()
+ delay_master_busy = Signal()
+ delay_slave_cal = Signal()
+ delay_slave_rst = Signal()
+ delay_slave_busy = Signal()
+ self.specials += Instance("IODELAY2",
+ p_SERDES_MODE="MASTER",
+ p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
+ p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR",
+
+ i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_master,
+ i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"),
+
+ i_INC=delay_inc, i_CE=delay_ce,
+ i_CAL=delay_master_cal, i_RST=delay_master_rst, o_BUSY=delay_master_busy,
+ i_T=1)
+ self.specials += Instance("IODELAY2",
+ p_SERDES_MODE="SLAVE",
+ p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
+ p_COUNTER_WRAPAROUND="WRAPAROUND", p_DATA_RATE="SDR",
+
+ i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_slave,
+ i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"),
+
+ i_INC=delay_inc, i_CE=delay_ce,
+ i_CAL=delay_slave_cal, i_RST=delay_slave_rst, o_BUSY=delay_slave_busy,
+ i_T=1)
+
+ dsr2 = Signal(5)
+ pd_valid = Signal()
+ pd_incdec = Signal()
+ pd_edge = Signal()
+ pd_cascade = Signal()
+ self.specials += Instance("ISERDES2",
+ p_SERDES_MODE="MASTER",
+ p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5,
+ p_INTERFACE_TYPE="RETIMED",
+
+ i_D=pad_delayed_master,
+ o_Q4=dsr2[4], o_Q3=dsr2[3], o_Q2=dsr2[2], o_Q1=dsr2[1],
+
+ i_BITSLIP=0, i_CE0=1, i_RST=0,
+ i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"),
+ i_IOCE=self.serdesstrobe,
+
+ o_VALID=pd_valid, o_INCDEC=pd_incdec,
+ i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade)
+ self.specials += Instance("ISERDES2",
+ p_SERDES_MODE="SLAVE",
+ p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5,
+ p_INTERFACE_TYPE="RETIMED",
+
+ i_D=pad_delayed_slave,
+ o_Q4=dsr2[0],
+
+ i_BITSLIP=0, i_CE0=1, i_RST=0,
+ i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"),
+ i_IOCE=self.serdesstrobe,
+
+ i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge)
+
+ # Phase error accumulator
+ lateness = Signal(ntbits, reset=2**(ntbits - 1))
+ too_late = Signal()
+ too_early = Signal()
+ reset_lateness = Signal()
+ self.comb += [
+ too_late.eq(lateness == (2**ntbits - 1)),
+ too_early.eq(lateness == 0)
+ ]
+ self.sync.pix2x += [
+ If(reset_lateness,
+ lateness.eq(2**(ntbits - 1))
+ ).Elif(~delay_master_busy & ~delay_slave_busy & ~too_late & ~too_early,
+ If(pd_valid & pd_incdec, lateness.eq(lateness - 1)),
+ If(pd_valid & ~pd_incdec, lateness.eq(lateness + 1))
+ )
+ ]
+
+ # Delay control
+ self.submodules.delay_master_done = PulseSynchronizer("pix2x", "sys")
+ delay_master_pending = Signal()
+ self.sync.pix2x += [
+ self.delay_master_done.i.eq(0),
+ If(~delay_master_pending,
+ If(delay_master_cal | delay_ce, delay_master_pending.eq(1))
+ ).Else(
+ If(~delay_master_busy,
+ self.delay_master_done.i.eq(1),
+ delay_master_pending.eq(0)
+ )
+ )
+ ]
+ self.submodules.delay_slave_done = PulseSynchronizer("pix2x", "sys")
+ delay_slave_pending = Signal()
+ self.sync.pix2x += [
+ self.delay_slave_done.i.eq(0),
+ If(~delay_slave_pending,
+ If(delay_slave_cal | delay_ce, delay_slave_pending.eq(1))
+ ).Else(
+ If(~delay_slave_busy,
+ self.delay_slave_done.i.eq(1),
+ delay_slave_pending.eq(0)
+ )
+ )
+ ]
+
+ self.submodules.do_delay_master_cal = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_master_rst = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_slave_cal = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_slave_rst = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix2x")
+ self.comb += [
+ delay_master_cal.eq(self.do_delay_master_cal.o),
+ delay_master_rst.eq(self.do_delay_master_rst.o),
+ delay_slave_cal.eq(self.do_delay_slave_cal.o),
+ delay_slave_rst.eq(self.do_delay_slave_rst.o),
+ delay_inc.eq(self.do_delay_inc.o),
+ delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o),
+ ]
+
+ sys_delay_master_pending = Signal()
+ self.sync += [
+ If(self.do_delay_master_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
+ sys_delay_master_pending.eq(1)
+ ).Elif(self.delay_master_done.o,
+ sys_delay_master_pending.eq(0)
+ )
+ ]
+ sys_delay_slave_pending = Signal()
+ self.sync += [
+ If(self.do_delay_slave_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
+ sys_delay_slave_pending.eq(1)
+ ).Elif(self.delay_slave_done.o,
+ sys_delay_slave_pending.eq(0)
+ )
+ ]
+
+ self.comb += [
+ self.do_delay_master_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[0]),
+ self.do_delay_master_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[1]),
+ self.do_delay_slave_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[2]),
+ self.do_delay_slave_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[3]),
+ self.do_delay_inc.i.eq(self._dly_ctl.re & self._dly_ctl.r[4]),
+ self.do_delay_dec.i.eq(self._dly_ctl.re & self._dly_ctl.r[5]),
+ self._dly_busy.status.eq(Cat(sys_delay_master_pending, sys_delay_slave_pending))
+ ]
+
+ # Phase detector control
+ self.specials += MultiReg(Cat(too_late, too_early), self._phase.status)
+ self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix2x")
+ self.comb += [
+ reset_lateness.eq(self.do_reset_lateness.o),
+ self.do_reset_lateness.i.eq(self._phase_reset.re)
+ ]
+
+ # 5:10 deserialization
+ dsr = Signal(10)
+ self.sync.pix2x += dsr.eq(Cat(dsr[5:], dsr2))
+ self.sync.pix += self.d.eq(dsr)
--- /dev/null
+from migen import *
+from migen.genlib.fifo import AsyncFIFO
+from migen.genlib.record import layout_len
+from migen.bank.description import AutoCSR
+from migen.actorlib import structuring, spi
+
+from misoc.mem.sdram.frontend import dma_lasmi
+from misoc.dvisampler.edid import EDID
+from misoc.dvisampler.clocking import Clocking
+from misoc.dvisampler.datacapture import DataCapture
+
+
+class RawDVISampler(Module, AutoCSR):
+ def __init__(self, pads, asmiport):
+ self.submodules.edid = EDID(pads)
+ self.submodules.clocking = Clocking(pads)
+
+ invert = False
+ try:
+ s = getattr(pads, "data0")
+ except AttributeError:
+ s = getattr(pads, "data0_n")
+ invert = True
+ self.submodules.data0_cap = DataCapture(8, invert)
+ self.comb += [
+ self.data0_cap.pad.eq(s),
+ self.data0_cap.serdesstrobe.eq(self.clocking.serdesstrobe)
+ ]
+
+ fifo = RenameClockDomains(AsyncFIFO(10, 256),
+ {"write": "pix", "read": "sys"})
+ self.submodules += fifo
+ self.comb += [
+ fifo.din.eq(self.data0_cap.d),
+ fifo.we.eq(1)
+ ]
+
+ pack_factor = asmiport.hub.dw//16
+ self.submodules.packer = structuring.Pack([("word", 10), ("pad", 6)], pack_factor)
+ self.submodules.cast = structuring.Cast(self.packer.source.payload.layout, asmiport.hub.dw)
+ self.submodules.dma = spi.DMAWriteController(dma_lasmi.Writer(lasmim), spi.MODE_SINGLE_SHOT)
+ self.comb += [
+ self.packer.sink.stb.eq(fifo.readable),
+ fifo.re.eq(self.packer.sink.ack),
+ self.packer.sink.word.eq(fifo.dout),
+ self.packer.source.connect_flat(self.cast.sink),
+ self.cast.source.connect_flat(self.dma.data)
+ ]
--- /dev/null
+from migen import *
+from migen.genlib.record import Record
+
+from misoc.dvisampler.common import control_tokens, channel_layout
+
+
+class Decoding(Module):
+ def __init__(self):
+ self.valid_i = Signal()
+ self.input = Signal(10)
+ self.valid_o = Signal()
+ self.output = Record(channel_layout)
+
+ ###
+
+ self.sync.pix += self.output.de.eq(1)
+ for i, t in enumerate(control_tokens):
+ self.sync.pix += If(self.input == t,
+ self.output.de.eq(0),
+ self.output.c.eq(i)
+ )
+ self.sync.pix += self.output.d[0].eq(self.input[0] ^ self.input[9])
+ for i in range(1, 8):
+ self.sync.pix += self.output.d[i].eq(self.input[i] ^ self.input[i-1] ^ ~self.input[8])
+ self.sync.pix += self.valid_o.eq(self.valid_i)
--- /dev/null
+from migen import *
+from migen.genlib.fsm import FSM, NextState
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+from migen.flow.actor import *
+
+from misoc.mem.sdram.frontend import dma_lasmi
+
+
+# Slot status: EMPTY=0 LOADED=1 PENDING=2
+class _Slot(Module, AutoCSR):
+ def __init__(self, addr_bits, alignment_bits):
+ self.ev_source = EventSourceLevel()
+ self.address = Signal(addr_bits)
+ self.address_reached = Signal(addr_bits)
+ self.address_valid = Signal()
+ self.address_done = Signal()
+
+ self._status = CSRStorage(2, write_from_dev=True)
+ self._address = CSRStorage(addr_bits + alignment_bits, alignment_bits=alignment_bits, write_from_dev=True)
+
+ ###
+
+ self.comb += [
+ self.address.eq(self._address.storage),
+ self.address_valid.eq(self._status.storage[0]),
+ self._status.dat_w.eq(2),
+ self._status.we.eq(self.address_done),
+ self._address.dat_w.eq(self.address_reached),
+ self._address.we.eq(self.address_done),
+ self.ev_source.trigger.eq(self._status.storage[1])
+ ]
+
+
+class _SlotArray(Module, AutoCSR):
+ def __init__(self, nslots, addr_bits, alignment_bits):
+ self.submodules.ev = EventManager()
+ self.address = Signal(addr_bits)
+ self.address_reached = Signal(addr_bits)
+ self.address_valid = Signal()
+ self.address_done = Signal()
+
+ ###
+
+ slots = [_Slot(addr_bits, alignment_bits) for i in range(nslots)]
+ for n, slot in enumerate(slots):
+ setattr(self.submodules, "slot"+str(n), slot)
+ setattr(self.ev, "slot"+str(n), slot.ev_source)
+ self.ev.finalize()
+
+ change_slot = Signal()
+ current_slot = Signal(max=nslots)
+ self.sync += If(change_slot, [If(slot.address_valid, current_slot.eq(n)) for n, slot in reversed(list(enumerate(slots)))])
+ self.comb += change_slot.eq(~self.address_valid | self.address_done)
+
+ self.comb += [
+ self.address.eq(Array(slot.address for slot in slots)[current_slot]),
+ self.address_valid.eq(Array(slot.address_valid for slot in slots)[current_slot])
+ ]
+ self.comb += [slot.address_reached.eq(self.address_reached) for slot in slots]
+ self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)]
+
+
+class DMA(Module):
+ def __init__(self, lasmim, nslots):
+ bus_aw = lasmim.aw
+ bus_dw = lasmim.dw
+ alignment_bits = bits_for(bus_dw//8) - 1
+
+ fifo_word_width = 24*bus_dw//32
+ self.frame = Sink([("sof", 1), ("pixels", fifo_word_width)])
+ self._frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits)
+ self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits)
+ self.ev = self._slot_array.ev
+
+ ###
+
+ # address generator + maximum memory word count to prevent DMA buffer overrun
+ reset_words = Signal()
+ count_word = Signal()
+ last_word = Signal()
+ current_address = Signal(bus_aw)
+ mwords_remaining = Signal(bus_aw)
+ self.comb += [
+ self._slot_array.address_reached.eq(current_address),
+ last_word.eq(mwords_remaining == 1)
+ ]
+ self.sync += [
+ If(reset_words,
+ current_address.eq(self._slot_array.address),
+ mwords_remaining.eq(self._frame_size.storage)
+ ).Elif(count_word,
+ current_address.eq(current_address + 1),
+ mwords_remaining.eq(mwords_remaining - 1)
+ )
+ ]
+
+ # 24bpp -> 32bpp
+ memory_word = Signal(bus_dw)
+ pixbits = []
+ for i in range(bus_dw//32):
+ for j in range(3):
+ b = (i*3+j)*8
+ pixbits.append(self.frame.pixels[b+6:b+8])
+ pixbits.append(self.frame.pixels[b:b+8])
+ pixbits.append(0)
+ pixbits.append(0)
+ self.comb += memory_word.eq(Cat(*pixbits))
+
+ # bus accessor
+ self.submodules._bus_accessor = dma_lasmi.Writer(lasmim)
+ self.comb += [
+ self._bus_accessor.address_data.a.eq(current_address),
+ self._bus_accessor.address_data.d.eq(memory_word)
+ ]
+
+ # control FSM
+ fsm = FSM()
+ self.submodules += fsm
+
+ fsm.act("WAIT_SOF",
+ reset_words.eq(1),
+ self.frame.ack.eq(~self._slot_array.address_valid | ~self.frame.sof),
+ If(self._slot_array.address_valid & self.frame.sof & self.frame.stb, NextState("TRANSFER_PIXELS"))
+ )
+ fsm.act("TRANSFER_PIXELS",
+ self.frame.ack.eq(self._bus_accessor.address_data.ack),
+ If(self.frame.stb,
+ self._bus_accessor.address_data.stb.eq(1),
+ If(self._bus_accessor.address_data.ack,
+ count_word.eq(1),
+ If(last_word, NextState("EOF"))
+ )
+ )
+ )
+ fsm.act("EOF",
+ If(~self._bus_accessor.busy,
+ self._slot_array.address_done.eq(1),
+ NextState("WAIT_SOF")
+ )
+ )
+
+ def get_csrs(self):
+ return [self._frame_size] + self._slot_array.get_csrs()
--- /dev/null
+from migen import *
+from migen.fhdl.specials import Tristate
+from migen.genlib.cdc import MultiReg
+from migen.genlib.fsm import FSM, NextState
+from migen.genlib.misc import chooser
+from migen.bank.description import CSRStorage, CSRStatus, AutoCSR
+
+_default_edid = [
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3D, 0x17, 0x32, 0x12, 0x2A, 0x6A, 0xBF, 0x00,
+ 0x05, 0x17, 0x01, 0x03, 0x80, 0x28, 0x1E, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xB2, 0x0C, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88,
+ 0x36, 0x00, 0x28, 0x1E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x4D, 0x31, 0x20,
+ 0x44, 0x56, 0x49, 0x20, 0x6D, 0x69, 0x78, 0x65, 0x72, 0x0A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34,
+]
+
+
+class EDID(Module, AutoCSR):
+ def __init__(self, pads, default=_default_edid):
+ self._hpd_notif = CSRStatus()
+ self._hpd_en = CSRStorage()
+ self.specials.mem = Memory(8, 128, init=default)
+
+ ###
+
+ # HPD
+ if hasattr(pads, "hpd_notif"):
+ self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status)
+ else:
+ self.comb += self._hpd_notif.status.eq(1)
+ if hasattr(pads, "hpd_en"):
+ self.comb += pads.hpd_en.eq(self._hpd_en.storage)
+
+ # EDID
+ scl_raw = Signal()
+ sda_i = Signal()
+ sda_raw = Signal()
+ sda_drv = Signal()
+ _sda_drv_reg = Signal()
+ _sda_i_async = Signal()
+ self.sync += _sda_drv_reg.eq(sda_drv)
+ self.specials += [
+ MultiReg(pads.scl, scl_raw),
+ Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async),
+ MultiReg(_sda_i_async, sda_raw)
+ ]
+
+ scl_i = Signal()
+ samp_count = Signal(6)
+ samp_carry = Signal()
+ self.sync += [
+ Cat(samp_count, samp_carry).eq(samp_count + 1),
+ If(samp_carry,
+ scl_i.eq(scl_raw),
+ sda_i.eq(sda_raw)
+ )
+ ]
+
+ scl_r = Signal()
+ sda_r = Signal()
+ scl_rising = Signal()
+ sda_rising = Signal()
+ sda_falling = Signal()
+ self.sync += [
+ scl_r.eq(scl_i),
+ sda_r.eq(sda_i)
+ ]
+ self.comb += [
+ scl_rising.eq(scl_i & ~scl_r),
+ sda_rising.eq(sda_i & ~sda_r),
+ sda_falling.eq(~sda_i & sda_r)
+ ]
+
+ start = Signal()
+ self.comb += start.eq(scl_i & sda_falling)
+
+ din = Signal(8)
+ counter = Signal(max=9)
+ self.sync += [
+ If(start, counter.eq(0)),
+ If(scl_rising,
+ If(counter == 8,
+ counter.eq(0)
+ ).Else(
+ counter.eq(counter + 1),
+ din.eq(Cat(sda_i, din[:7]))
+ )
+ )
+ ]
+
+ is_read = Signal()
+ update_is_read = Signal()
+ self.sync += If(update_is_read, is_read.eq(din[0]))
+
+ offset_counter = Signal(max=128)
+ oc_load = Signal()
+ oc_inc = Signal()
+ self.sync += [
+ If(oc_load,
+ offset_counter.eq(din)
+ ).Elif(oc_inc,
+ offset_counter.eq(offset_counter + 1)
+ )
+ ]
+ rdport = self.mem.get_port()
+ self.specials += rdport
+ self.comb += rdport.adr.eq(offset_counter)
+ data_bit = Signal()
+
+ zero_drv = Signal()
+ data_drv = Signal()
+ self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit))
+
+ data_drv_en = Signal()
+ data_drv_stop = Signal()
+ self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0))
+ self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True))
+
+ fsm = FSM()
+ self.submodules += fsm
+
+ fsm.act("WAIT_START")
+ fsm.act("RCV_ADDRESS",
+ If(counter == 8,
+ If(din[1:] == 0x50,
+ update_is_read.eq(1),
+ NextState("ACK_ADDRESS0")
+ ).Else(
+ NextState("WAIT_START")
+ )
+ )
+ )
+ fsm.act("ACK_ADDRESS0",
+ If(~scl_i, NextState("ACK_ADDRESS1"))
+ )
+ fsm.act("ACK_ADDRESS1",
+ zero_drv.eq(1),
+ If(scl_i, NextState("ACK_ADDRESS2"))
+ )
+ fsm.act("ACK_ADDRESS2",
+ zero_drv.eq(1),
+ If(~scl_i,
+ If(is_read,
+ NextState("READ")
+ ).Else(
+ NextState("RCV_OFFSET")
+ )
+ )
+ )
+
+ fsm.act("RCV_OFFSET",
+ If(counter == 8,
+ oc_load.eq(1),
+ NextState("ACK_OFFSET0")
+ )
+ )
+ fsm.act("ACK_OFFSET0",
+ If(~scl_i, NextState("ACK_OFFSET1"))
+ )
+ fsm.act("ACK_OFFSET1",
+ zero_drv.eq(1),
+ If(scl_i, NextState("ACK_OFFSET2"))
+ )
+ fsm.act("ACK_OFFSET2",
+ zero_drv.eq(1),
+ If(~scl_i, NextState("RCV_ADDRESS"))
+ )
+
+ fsm.act("READ",
+ If(~scl_i,
+ If(counter == 8,
+ data_drv_stop.eq(1),
+ NextState("ACK_READ")
+ ).Else(
+ data_drv_en.eq(1)
+ )
+ )
+ )
+ fsm.act("ACK_READ",
+ If(scl_rising,
+ oc_inc.eq(1),
+ If(sda_i,
+ NextState("WAIT_START")
+ ).Else(
+ NextState("READ")
+ )
+ )
+ )
+
+ for state in fsm.actions.keys():
+ fsm.act(state, If(start, NextState("RCV_ADDRESS")))
+ fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START")))
--- /dev/null
+from migen import *
+from migen.bank.description import *
+from migen.genlib.misc import optree
+from migen.genlib.cdc import PulseSynchronizer
+
+from misoc.dvisampler.common import control_tokens
+
+
+class WER(Module, AutoCSR):
+ def __init__(self, period_bits=24):
+ self.data = Signal(10)
+ self._update = CSR()
+ self._value = CSRStatus(period_bits)
+
+ ###
+
+ # pipeline stage 1
+ # we ignore the 10th (inversion) bit, as it is independent of the transition minimization
+ data_r = Signal(9)
+ self.sync.pix += data_r.eq(self.data[:9])
+
+ # pipeline stage 2
+ transitions = Signal(8)
+ self.comb += [transitions[i].eq(data_r[i] ^ data_r[i+1]) for i in range(8)]
+ transition_count = Signal(max=9)
+ self.sync.pix += transition_count.eq(optree("+", [transitions[i] for i in range(8)]))
+
+ is_control = Signal()
+ self.sync.pix += is_control.eq(optree("|", [data_r == ct for ct in control_tokens]))
+
+ # pipeline stage 3
+ is_error = Signal()
+ self.sync.pix += is_error.eq((transition_count > 4) & ~is_control)
+
+ # counter
+ period_counter = Signal(period_bits)
+ period_done = Signal()
+ self.sync.pix += Cat(period_counter, period_done).eq(period_counter + 1)
+
+ wer_counter = Signal(period_bits)
+ wer_counter_r = Signal(period_bits)
+ wer_counter_r_updated = Signal()
+ self.sync.pix += [
+ wer_counter_r_updated.eq(period_done),
+ If(period_done,
+ wer_counter_r.eq(wer_counter),
+ wer_counter.eq(0)
+ ).Elif(is_error,
+ wer_counter.eq(wer_counter + 1)
+ )
+ ]
+
+ # sync to system clock domain
+ wer_counter_sys = Signal(period_bits)
+ self.submodules.ps_counter = PulseSynchronizer("pix", "sys")
+ self.comb += self.ps_counter.i.eq(wer_counter_r_updated)
+ self.sync += If(self.ps_counter.o, wer_counter_sys.eq(wer_counter_r))
+
+ # register interface
+ self.sync += If(self._update.re, self._value.status.eq(wer_counter_sys))
--- /dev/null
+from misoc.framebuffer.core import Framebuffer
--- /dev/null
+from migen import *
+from migen.flow.network import *
+from migen.flow import plumbing
+from migen.bank.description import AutoCSR
+from migen.actorlib import structuring, misc
+
+from misoc.mem.sdram.frontend import dma_lasmi
+from misoc.framebuffer.format import bpp, pixel_layout, FrameInitiator, VTG
+from misoc.framebuffer.phy import Driver
+
+
+class Framebuffer(Module, AutoCSR):
+ def __init__(self, pads_vga, pads_dvi, lasmim):
+ pack_factor = lasmim.dw//bpp
+
+ g = DataFlowGraph()
+
+ self.fi = FrameInitiator(lasmim.aw, pack_factor)
+
+ intseq = misc.IntSequence(lasmim.aw, lasmim.aw)
+ dma_out = AbstractActor(plumbing.Buffer)
+ g.add_connection(self.fi, intseq, source_subr=self.fi.dma_subr())
+ g.add_pipeline(intseq, AbstractActor(plumbing.Buffer), dma_lasmi.Reader(lasmim), dma_out)
+
+ cast = structuring.Cast(lasmim.dw, pixel_layout(pack_factor), reverse_to=True)
+ vtg = VTG(pack_factor)
+ self.driver = Driver(pack_factor, pads_vga, pads_dvi)
+
+ g.add_connection(self.fi, vtg, source_subr=self.fi.timing_subr, sink_ep="timing")
+ g.add_connection(dma_out, cast)
+ g.add_connection(cast, vtg, sink_ep="pixels")
+ g.add_connection(vtg, self.driver)
+ self.submodules += CompositeActor(g)
--- /dev/null
+from migen import *
+from migen.genlib.misc import optree
+
+control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
+
+
+class Encoder(Module):
+ def __init__(self):
+ self.d = Signal(8)
+ self.c = Signal(2)
+ self.de = Signal()
+
+ self.out = Signal(10)
+
+ ###
+
+ # stage 1 - count number of 1s in data
+ d = Signal(8)
+ n1d = Signal(max=9)
+ self.sync += [
+ n1d.eq(optree("+", [self.d[i] for i in range(8)])),
+ d.eq(self.d)
+ ]
+
+ # stage 2 - add 9th bit
+ q_m = Signal(9)
+ q_m8_n = Signal()
+ self.comb += q_m8_n.eq((n1d > 4) | ((n1d == 4) & ~d[0]))
+ for i in range(8):
+ if i:
+ curval = curval ^ d[i] ^ q_m8_n
+ else:
+ curval = d[0]
+ self.sync += q_m[i].eq(curval)
+ self.sync += q_m[8].eq(~q_m8_n)
+
+ # stage 3 - count number of 1s and 0s in q_m[:8]
+ q_m_r = Signal(9)
+ n0q_m = Signal(max=9)
+ n1q_m = Signal(max=9)
+ self.sync += [
+ n0q_m.eq(optree("+", [~q_m[i] for i in range(8)])),
+ n1q_m.eq(optree("+", [q_m[i] for i in range(8)])),
+ q_m_r.eq(q_m)
+ ]
+
+ # stage 4 - final encoding
+ cnt = Signal((6, True))
+
+ s_c = self.c
+ s_de = self.de
+ for p in range(3):
+ new_c = Signal(2)
+ new_de = Signal()
+ self.sync += new_c.eq(s_c), new_de.eq(s_de)
+ s_c, s_de = new_c, new_de
+
+ self.sync += If(s_de,
+ If((cnt == 0) | (n1q_m == n0q_m),
+ self.out[9].eq(~q_m_r[8]),
+ self.out[8].eq(q_m_r[8]),
+ If(q_m_r[8],
+ self.out[:8].eq(q_m_r[:8]),
+ cnt.eq(cnt + n1q_m - n0q_m)
+ ).Else(
+ self.out[:8].eq(~q_m_r[:8]),
+ cnt.eq(cnt + n0q_m - n1q_m)
+ )
+ ).Else(
+ If((~cnt[5] & (n1q_m > n0q_m)) | (cnt[5] & (n0q_m > n1q_m)),
+ self.out[9].eq(1),
+ self.out[8].eq(q_m_r[8]),
+ self.out[:8].eq(~q_m_r[:8]),
+ cnt.eq(cnt + Cat(0, q_m_r[8]) + n0q_m - n1q_m)
+ ).Else(
+ self.out[9].eq(0),
+ self.out[8].eq(q_m_r[8]),
+ self.out[:8].eq(q_m_r[:8]),
+ cnt.eq(cnt - Cat(0, ~q_m_r[8]) + n1q_m - n0q_m)
+ )
+ )
+ ).Else(
+ self.out.eq(Array(control_tokens)[s_c]),
+ cnt.eq(0)
+ )
+
+
+class _EncoderSerializer(Module):
+ def __init__(self, serdesstrobe, pad_p, pad_n):
+ self.submodules.encoder = RenameClockDomains(Encoder(), "pix")
+ self.d, self.c, self.de = self.encoder.d, self.encoder.c, self.encoder.de
+
+ ###
+
+ # 2X soft serialization
+ ed_2x = Signal(5)
+ self.sync.pix2x += ed_2x.eq(Mux(ClockSignal("pix"), self.encoder.out[:5], self.encoder.out[5:]))
+
+ # 5X hard serialization
+ cascade_di = Signal()
+ cascade_do = Signal()
+ cascade_ti = Signal()
+ cascade_to = Signal()
+ pad_se = Signal()
+ self.specials += [
+ Instance("OSERDES2",
+ p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
+ p_SERDES_MODE="MASTER", p_OUTPUT_MODE="DIFFERENTIAL",
+
+ o_OQ=pad_se,
+ i_OCE=1, i_IOCE=serdesstrobe, i_RST=0,
+ i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"),
+ i_D1=ed_2x[4], i_D2=0, i_D3=0, i_D4=0,
+ i_T1=0, i_T2=0, i_T3=0, i_T4=0,
+ i_TRAIN=0, i_TCE=1,
+ i_SHIFTIN1=1, i_SHIFTIN2=1,
+ i_SHIFTIN3=cascade_do, i_SHIFTIN4=cascade_to,
+ o_SHIFTOUT1=cascade_di, o_SHIFTOUT2=cascade_ti),
+ Instance("OSERDES2",
+ p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
+ p_SERDES_MODE="SLAVE", p_OUTPUT_MODE="DIFFERENTIAL",
+
+ i_OCE=1, i_IOCE=serdesstrobe, i_RST=0,
+ i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"),
+ i_D1=ed_2x[0], i_D2=ed_2x[1], i_D3=ed_2x[2], i_D4=ed_2x[3],
+ i_T1=0, i_T2=0, i_T3=0, i_T4=0,
+ i_TRAIN=0, i_TCE=1,
+ i_SHIFTIN1=cascade_di, i_SHIFTIN2=cascade_ti,
+ i_SHIFTIN3=1, i_SHIFTIN4=1,
+ o_SHIFTOUT3=cascade_do, o_SHIFTOUT4=cascade_to),
+ Instance("OBUFDS", i_I=pad_se, o_O=pad_p, o_OB=pad_n)
+ ]
+
+
+class PHY(Module):
+ def __init__(self, serdesstrobe, pads):
+ self.hsync = Signal()
+ self.vsync = Signal()
+ self.de = Signal()
+ self.r = Signal(8)
+ self.g = Signal(8)
+ self.b = Signal(8)
+
+ ###
+
+ self.submodules.es0 = _EncoderSerializer(serdesstrobe, pads.data0_p, pads.data0_n)
+ self.submodules.es1 = _EncoderSerializer(serdesstrobe, pads.data1_p, pads.data1_n)
+ self.submodules.es2 = _EncoderSerializer(serdesstrobe, pads.data2_p, pads.data2_n)
+ self.comb += [
+ self.es0.d.eq(self.r),
+ self.es1.d.eq(self.g),
+ self.es2.d.eq(self.b),
+ self.es0.c.eq(Cat(self.hsync, self.vsync)),
+ self.es1.c.eq(0),
+ self.es2.c.eq(0),
+ self.es0.de.eq(self.de),
+ self.es1.de.eq(self.de),
+ self.es2.de.eq(self.de),
+ ]
+
+
+class _EncoderTB(Module):
+ def __init__(self, inputs):
+ self.outs = []
+ self._iter_inputs = iter(inputs)
+ self._end_cycle = None
+ self.submodules.dut = Encoder()
+ self.comb += self.dut.de.eq(1)
+
+ def do_simulation(self, selfp):
+ if self._end_cycle is None:
+ try:
+ nv = next(self._iter_inputs)
+ except StopIteration:
+ self._end_cycle = selfp.simulator.cycle_counter + 4
+ else:
+ selfp.dut.d = nv
+ if selfp.simulator.cycle_counter == self._end_cycle:
+ raise StopSimulation
+ if selfp.simulator.cycle_counter > 4:
+ self.outs.append(selfp.dut.out)
+
+
+def _bit(i, n):
+ return (i >> n) & 1
+
+
+def _decode_tmds(b):
+ try:
+ c = control_tokens.index(b)
+ de = False
+ except ValueError:
+ c = 0
+ de = True
+ vsync = bool(c & 2)
+ hsync = bool(c & 1)
+
+ value = _bit(b, 0) ^ _bit(b, 9)
+ for i in range(1, 8):
+ value |= (_bit(b, i) ^ _bit(b, i-1) ^ (~_bit(b, 8) & 1)) << i
+
+ return de, hsync, vsync, value
+
+if __name__ == "__main__":
+ from migen.sim.generic import run_simulation
+ from random import Random
+
+ rng = Random(788)
+ test_list = [rng.randrange(256) for i in range(500)]
+ tb = _EncoderTB(test_list)
+ run_simulation(tb)
+
+ check = [_decode_tmds(out)[3] for out in tb.outs]
+ assert(check == test_list)
+
+ nb0 = 0
+ nb1 = 0
+ for out in tb.outs:
+ for i in range(10):
+ if _bit(out, i):
+ nb1 += 1
+ else:
+ nb0 += 1
+ print("0/1: {}/{} ({:.2f})".format(nb0, nb1, nb0/nb1))
--- /dev/null
+from migen import *
+from migen.flow.actor import *
+from migen.bank.description import CSRStorage
+from migen.genlib.record import Record
+from migen.genlib.fsm import FSM, NextState
+from migen.actorlib import spi
+
+_hbits = 12
+_vbits = 12
+
+bpp = 32
+bpc = 10
+pixel_layout_s = [
+ ("pad", bpp-3*bpc),
+ ("r", bpc),
+ ("g", bpc),
+ ("b", bpc)
+]
+
+
+def pixel_layout(pack_factor):
+ return [("p"+str(i), pixel_layout_s) for i in range(pack_factor)]
+
+bpc_phy = 8
+phy_layout_s = [
+ ("r", bpc_phy),
+ ("g", bpc_phy),
+ ("b", bpc_phy)
+]
+
+
+def phy_layout(pack_factor):
+ r = [("hsync", 1), ("vsync", 1), ("de", 1)]
+ for i in range(pack_factor):
+ r.append(("p"+str(i), phy_layout_s))
+ return r
+
+
+class FrameInitiator(spi.SingleGenerator):
+ def __init__(self, bus_aw, pack_factor, ndmas=1):
+ h_alignment_bits = log2_int(pack_factor)
+ hbits_dyn = _hbits - h_alignment_bits
+ bus_alignment_bits = h_alignment_bits + log2_int(bpp//8)
+ layout = [
+ ("hres", hbits_dyn, 640, h_alignment_bits),
+ ("hsync_start", hbits_dyn, 656, h_alignment_bits),
+ ("hsync_end", hbits_dyn, 752, h_alignment_bits),
+ ("hscan", hbits_dyn, 800, h_alignment_bits),
+
+ ("vres", _vbits, 480),
+ ("vsync_start", _vbits, 492),
+ ("vsync_end", _vbits, 494),
+ ("vscan", _vbits, 525),
+
+ ("length", bus_aw + bus_alignment_bits, 640*480*bpp//8, bus_alignment_bits)
+ ]
+ layout += [("base"+str(i), bus_aw + bus_alignment_bits, 0, bus_alignment_bits)
+ for i in range(ndmas)]
+ spi.SingleGenerator.__init__(self, layout, spi.MODE_CONTINUOUS)
+
+ timing_subr = ["hres", "hsync_start", "hsync_end", "hscan",
+ "vres", "vsync_start", "vsync_end", "vscan"]
+
+ def dma_subr(self, i=0):
+ return ["length", "base"+str(i)]
+
+
+class VTG(Module):
+ def __init__(self, pack_factor):
+ hbits_dyn = _hbits - log2_int(pack_factor)
+ timing_layout = [
+ ("hres", hbits_dyn),
+ ("hsync_start", hbits_dyn),
+ ("hsync_end", hbits_dyn),
+ ("hscan", hbits_dyn),
+ ("vres", _vbits),
+ ("vsync_start", _vbits),
+ ("vsync_end", _vbits),
+ ("vscan", _vbits)]
+ self.timing = Sink(timing_layout)
+ self.pixels = Sink(pixel_layout(pack_factor))
+ self.phy = Source(phy_layout(pack_factor))
+ self.busy = Signal()
+
+ ###
+
+ hactive = Signal()
+ vactive = Signal()
+ active = Signal()
+
+ hcounter = Signal(hbits_dyn)
+ vcounter = Signal(_vbits)
+
+ skip = bpc - bpc_phy
+ self.comb += [
+ active.eq(hactive & vactive),
+ If(active,
+ [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:])
+ for p in ["p"+str(i) for i in range(pack_factor)] for c in ["r", "g", "b"]],
+ self.phy.de.eq(1)
+ ),
+ self.pixels.ack.eq(self.phy.ack & active)
+ ]
+
+ load_timing = Signal()
+ tr = Record(timing_layout)
+ self.sync += If(load_timing, tr.eq(self.timing.payload))
+
+ generate_en = Signal()
+ generate_frame_done = Signal()
+ self.sync += [
+ generate_frame_done.eq(0),
+ If(generate_en,
+ hcounter.eq(hcounter + 1),
+
+ If(hcounter == 0, hactive.eq(1)),
+ If(hcounter == tr.hres, hactive.eq(0)),
+ If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)),
+ If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)),
+ If(hcounter == tr.hscan,
+ hcounter.eq(0),
+ If(vcounter == tr.vscan,
+ vcounter.eq(0),
+ generate_frame_done.eq(1)
+ ).Else(
+ vcounter.eq(vcounter + 1)
+ )
+ ),
+
+ If(vcounter == 0, vactive.eq(1)),
+ If(vcounter == tr.vres, vactive.eq(0)),
+ If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)),
+ If(vcounter == tr.vsync_end, self.phy.vsync.eq(0))
+ )
+ ]
+
+ self.submodules.fsm = FSM()
+ self.fsm.act("GET_TIMING",
+ self.timing.ack.eq(1),
+ load_timing.eq(1),
+ If(self.timing.stb, NextState("GENERATE"))
+ )
+ self.fsm.act("GENERATE",
+ self.busy.eq(1),
+ If(~active | self.pixels.stb,
+ self.phy.stb.eq(1),
+ If(self.phy.ack, generate_en.eq(1))
+ ),
+ If(generate_frame_done, NextState("GET_TIMING"))
+ )
--- /dev/null
+from migen import *
+from migen.genlib.fifo import AsyncFIFO
+from migen.genlib.cdc import MultiReg
+from migen.bank.description import *
+from migen.flow.actor import *
+
+from misoc.framebuffer.format import bpc_phy, phy_layout
+from misoc.framebuffer import dvi
+
+
+class _FIFO(Module):
+ def __init__(self, pack_factor):
+ self.phy = Sink(phy_layout(pack_factor))
+ self.busy = Signal()
+
+ self.pix_hsync = Signal()
+ self.pix_vsync = Signal()
+ self.pix_de = Signal()
+ self.pix_r = Signal(bpc_phy)
+ self.pix_g = Signal(bpc_phy)
+ self.pix_b = Signal(bpc_phy)
+
+ ###
+
+ fifo = RenameClockDomains(AsyncFIFO(phy_layout(pack_factor), 512),
+ {"write": "sys", "read": "pix"})
+ self.submodules += fifo
+ self.comb += [
+ self.phy.ack.eq(fifo.writable),
+ fifo.we.eq(self.phy.stb),
+ fifo.din.eq(self.phy.payload),
+ self.busy.eq(0)
+ ]
+
+ unpack_counter = Signal(max=pack_factor)
+ assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
+ self.sync.pix += [
+ unpack_counter.eq(unpack_counter + 1),
+ self.pix_hsync.eq(fifo.dout.hsync),
+ self.pix_vsync.eq(fifo.dout.vsync),
+ self.pix_de.eq(fifo.dout.de)
+ ]
+ for i in range(pack_factor):
+ pixel = getattr(fifo.dout, "p"+str(i))
+ self.sync.pix += If(unpack_counter == i,
+ self.pix_r.eq(pixel.r),
+ self.pix_g.eq(pixel.g),
+ self.pix_b.eq(pixel.b)
+ )
+ self.comb += fifo.re.eq(unpack_counter == (pack_factor - 1))
+
+
+# This assumes a 50MHz base clock
+class _Clocking(Module, AutoCSR):
+ def __init__(self, pads_vga, pads_dvi):
+ self._cmd_data = CSRStorage(10)
+ self._send_cmd_data = CSR()
+ self._send_go = CSR()
+ self._status = CSRStatus(4)
+
+ self.clock_domains.cd_pix = ClockDomain(reset_less=True)
+ if pads_dvi is not None:
+ self._pll_reset = CSRStorage()
+ self._pll_adr = CSRStorage(5)
+ self._pll_dat_r = CSRStatus(16)
+ self._pll_dat_w = CSRStorage(16)
+ self._pll_read = CSR()
+ self._pll_write = CSR()
+ self._pll_drdy = CSRStatus()
+
+ self.clock_domains.cd_pix2x = ClockDomain(reset_less=True)
+ self.clock_domains.cd_pix10x = ClockDomain(reset_less=True)
+ self.serdesstrobe = Signal()
+
+ ###
+
+ # Generate 1x pixel clock
+ clk_pix_unbuffered = Signal()
+ pix_progdata = Signal()
+ pix_progen = Signal()
+ pix_progdone = Signal()
+ pix_locked = Signal()
+ self.specials += Instance("DCM_CLKGEN",
+ p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=4, p_CLKFX_MD_MAX=1.0, p_CLKFX_MULTIPLY=2,
+ p_CLKIN_PERIOD=20.0, p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE",
+
+ i_CLKIN=ClockSignal("base50"), o_CLKFX=clk_pix_unbuffered,
+ i_PROGCLK=ClockSignal(), i_PROGDATA=pix_progdata, i_PROGEN=pix_progen,
+ o_PROGDONE=pix_progdone, o_LOCKED=pix_locked,
+ i_FREEZEDCM=0, i_RST=ResetSignal())
+
+ remaining_bits = Signal(max=11)
+ transmitting = Signal()
+ self.comb += transmitting.eq(remaining_bits != 0)
+ sr = Signal(10)
+ self.sync += [
+ If(self._send_cmd_data.re,
+ remaining_bits.eq(10),
+ sr.eq(self._cmd_data.storage)
+ ).Elif(transmitting,
+ remaining_bits.eq(remaining_bits - 1),
+ sr.eq(sr[1:])
+ )
+ ]
+ self.comb += [
+ pix_progdata.eq(transmitting & sr[0]),
+ pix_progen.eq(transmitting | self._send_go.re)
+ ]
+
+ # enforce gap between commands
+ busy_counter = Signal(max=14)
+ busy = Signal()
+ self.comb += busy.eq(busy_counter != 0)
+ self.sync += If(self._send_cmd_data.re,
+ busy_counter.eq(13)
+ ).Elif(busy,
+ busy_counter.eq(busy_counter - 1)
+ )
+
+ mult_locked = Signal()
+ self.comb += self._status.status.eq(Cat(busy, pix_progdone, pix_locked, mult_locked))
+
+ # Clock multiplication and buffering
+ if pads_dvi is None:
+ # Just buffer 1x pixel clock
+ self.specials += Instance("BUFG", i_I=clk_pix_unbuffered, o_O=self.cd_pix.clk)
+ self.comb += mult_locked.eq(pix_locked)
+ else:
+ # Route unbuffered 1x pixel clock to PLL
+ # Generate 1x, 2x and 10x IO pixel clocks
+ clkfbout = Signal()
+ pll_locked = Signal()
+ pll_clk0 = Signal()
+ pll_clk1 = Signal()
+ pll_clk2 = Signal()
+ locked_async = Signal()
+ pll_drdy = Signal()
+ self.sync += If(self._pll_read.re | self._pll_write.re,
+ self._pll_drdy.status.eq(0)
+ ).Elif(pll_drdy,
+ self._pll_drdy.status.eq(1)
+ )
+ self.specials += [
+ Instance("PLL_ADV",
+ p_CLKFBOUT_MULT=10,
+ p_CLKOUT0_DIVIDE=1, # pix10x
+ p_CLKOUT1_DIVIDE=5, # pix2x
+ p_CLKOUT2_DIVIDE=10, # pix
+ p_COMPENSATION="INTERNAL",
+
+ i_CLKINSEL=1,
+ i_CLKIN1=clk_pix_unbuffered,
+ o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
+ o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
+ o_LOCKED=pll_locked,
+ i_RST=~pix_locked | self._pll_reset.storage,
+
+ i_DADDR=self._pll_adr.storage,
+ o_DO=self._pll_dat_r.status,
+ i_DI=self._pll_dat_w.storage,
+ i_DEN=self._pll_read.re | self._pll_write.re,
+ i_DWE=self._pll_write.re,
+ o_DRDY=pll_drdy,
+ i_DCLK=ClockSignal()),
+ Instance("BUFPLL", p_DIVIDE=5,
+ i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked,
+ o_IOCLK=self.cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
+ Instance("BUFG", i_I=pll_clk1, o_O=self.cd_pix2x.clk),
+ Instance("BUFG", name="dviout_pix_bufg", i_I=pll_clk2, o_O=self.cd_pix.clk),
+ MultiReg(locked_async, mult_locked, "sys")
+ ]
+
+ # Drive VGA/DVI clock pads
+ if pads_vga is not None:
+ self.specials += Instance("ODDR2",
+ p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
+ o_Q=pads_vga.clk,
+ i_C0=ClockSignal("pix"),
+ i_C1=~ClockSignal("pix"),
+ i_CE=1, i_D0=1, i_D1=0,
+ i_R=0, i_S=0)
+ if pads_dvi is not None:
+ dvi_clk_se = Signal()
+ self.specials += Instance("ODDR2",
+ p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
+ o_Q=dvi_clk_se,
+ i_C0=ClockSignal("pix"),
+ i_C1=~ClockSignal("pix"),
+ i_CE=1, i_D0=1, i_D1=0,
+ i_R=0, i_S=0)
+ self.specials += Instance("OBUFDS", i_I=dvi_clk_se,
+ o_O=pads_dvi.clk_p, o_OB=pads_dvi.clk_n)
+
+
+class Driver(Module, AutoCSR):
+ def __init__(self, pack_factor, pads_vga, pads_dvi):
+ fifo = _FIFO(pack_factor)
+ self.submodules += fifo
+ self.phy = fifo.phy
+ self.busy = fifo.busy
+
+ self.submodules.clocking = _Clocking(pads_vga, pads_dvi)
+
+ if pads_vga is not None:
+ self.comb += [
+ pads_vga.hsync_n.eq(~fifo.pix_hsync),
+ pads_vga.vsync_n.eq(~fifo.pix_vsync),
+ pads_vga.r.eq(fifo.pix_r),
+ pads_vga.g.eq(fifo.pix_g),
+ pads_vga.b.eq(fifo.pix_b),
+ pads_vga.psave_n.eq(1)
+ ]
+ if pads_dvi is not None:
+ self.submodules.dvi_phy = dvi.PHY(self.clocking.serdesstrobe, pads_dvi)
+ self.comb += [
+ self.dvi_phy.hsync.eq(fifo.pix_hsync),
+ self.dvi_phy.vsync.eq(fifo.pix_vsync),
+ self.dvi_phy.de.eq(fifo.pix_de),
+ self.dvi_phy.r.eq(fifo.pix_r),
+ self.dvi_phy.g.eq(fifo.pix_g),
+ self.dvi_phy.b.eq(fifo.pix_b)
+ ]
--- /dev/null
+from migen import *
+from migen.genlib.cdc import MultiReg
+from migen.bank.description import *
+
+
+class GPIOIn(Module, AutoCSR):
+ def __init__(self, signal):
+ self._in = CSRStatus(flen(signal))
+ self.specials += MultiReg(signal, self._in.status)
+
+
+class GPIOOut(Module, AutoCSR):
+ def __init__(self, signal):
+ self._out = CSRStorage(flen(signal))
+ self.comb += signal.eq(self._out.storage)
+
+
+class GPIOInOut(Module):
+ def __init__(self, in_signal, out_signal):
+ self.submodules.gpio_in = GPIOIn(in_signal)
+ self.submodules.gpio_out = GPIOOut(out_signal)
+
+ def get_csrs(self):
+ return self.gpio_in.get_csrs() + self.gpio_out.get_csrs()
+
+
+class Blinker(Module):
+ def __init__(self, signal, divbits=26):
+ counter = Signal(divbits)
+ self.comb += signal.eq(counter[divbits-1])
+ self.sync += counter.eq(counter + 1)
--- /dev/null
+import subprocess
+
+from migen import *
+from migen.bank.description import *
+
+def get_id():
+ output = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii")
+ return int(output[:8], 16)
+
+
+class Identifier(Module, AutoCSR):
+ def __init__(self, sysid, frequency, revision=None):
+ self._sysid = CSRStatus(16)
+ self._revision = CSRStatus(32)
+ self._frequency = CSRStatus(32)
+
+ ###
+
+ if revision is None:
+ revision = get_id()
+
+ self.comb += [
+ self._sysid.status.eq(sysid),
+ self._revision.status.eq(revision),
+ self._frequency.status.eq(frequency)
+ ]
--- /dev/null
+from misoc.integration.soc_core import SoCCore
+from misoc.integration.soc_sdram import SoCSDRAM
--- /dev/null
+from migen import *
+from migen.bank.description import CSRStatus
+
+
+def get_cpu_mak(cpu_type):
+ if cpu_type == "lm32":
+ triple = "lm32-elf"
+ cpuflags = "-mbarrel-shift-enabled -mmultiply-enabled -mdivide-enabled -msign-extend-enabled"
+ clang = ""
+ elif cpu_type == "or1k":
+ triple = "or1k-linux"
+ cpuflags = "-mhard-mul -mhard-div -mror -mffl1 -maddc"
+ clang = "1"
+ else:
+ raise ValueError("Unsupported CPU type: "+cpu_type)
+ return "TRIPLE={}\nCPU={}\nCPUFLAGS={}\nCLANG={}".format(triple, cpu_type, cpuflags, clang)
+
+
+def get_linker_output_format(cpu_type):
+ return "OUTPUT_FORMAT(\"elf32-{}\")\n".format(cpu_type)
+
+
+def get_linker_regions(regions):
+ r = "MEMORY {\n"
+ for name, origin, length in regions:
+ r += "\t{} : ORIGIN = 0x{:08x}, LENGTH = 0x{:08x}\n".format(name, origin, length)
+ r += "}\n"
+ return r
+
+
+def get_mem_header(regions, flash_boot_address):
+ r = "#ifndef __GENERATED_MEM_H\n#define __GENERATED_MEM_H\n\n"
+ for name, base, size in regions:
+ r += "#define {name}_BASE 0x{base:08x}\n#define {name}_SIZE 0x{size:08x}\n\n".format(name=name.upper(), base=base, size=size)
+ if flash_boot_address is not None:
+ r += "#define FLASH_BOOT_ADDRESS 0x{:08x}\n\n".format(flash_boot_address)
+ r += "#endif\n"
+ return r
+
+
+def _get_rw_functions(reg_name, reg_base, nwords, busword, read_only, with_access_functions):
+ r = ""
+
+ r += "#define CSR_"+reg_name.upper()+"_ADDR "+hex(reg_base)+"\n"
+ r += "#define CSR_"+reg_name.upper()+"_SIZE "+str(nwords)+"\n"
+
+ size = nwords*busword
+ if size > 64:
+ return r
+ elif size > 32:
+ ctype = "unsigned long long int"
+ elif size > 16:
+ ctype = "unsigned int"
+ elif size > 8:
+ ctype = "unsigned short int"
+ else:
+ ctype = "unsigned char"
+
+ if with_access_functions:
+ r += "static inline "+ctype+" "+reg_name+"_read(void) {\n"
+ if size > 1:
+ r += "\t"+ctype+" r = MMPTR("+hex(reg_base)+");\n"
+ for byte in range(1, nwords):
+ r += "\tr <<= "+str(busword)+";\n\tr |= MMPTR("+hex(reg_base+4*byte)+");\n"
+ r += "\treturn r;\n}\n"
+ else:
+ r += "\treturn MMPTR("+hex(reg_base)+");\n}\n"
+
+ if not read_only:
+ r += "static inline void "+reg_name+"_write("+ctype+" value) {\n"
+ for word in range(nwords):
+ shift = (nwords-word-1)*busword
+ if shift:
+ value_shifted = "value >> "+str(shift)
+ else:
+ value_shifted = "value"
+ r += "\tMMPTR("+hex(reg_base+4*word)+") = "+value_shifted+";\n"
+ r += "}\n"
+ return r
+
+
+def get_csr_header(regions, constants, with_access_functions=True):
+ r = "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n"
+ if with_access_functions:
+ r += "#include <hw/common.h>\n"
+ for name, origin, busword, obj in regions:
+ if isinstance(obj, Memory):
+ r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n"
+ else:
+ r += "\n/* "+name+" */\n"
+ r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n"
+ for csr in obj:
+ nr = (csr.size + busword - 1)//busword
+ r += _get_rw_functions(name + "_" + csr.name, origin, nr, busword, isinstance(csr, CSRStatus), with_access_functions)
+ origin += 4*nr
+
+ r += "\n/* constants */\n"
+ for name, value in constants:
+ r += "#define " + name
+ if value is not None:
+ if isinstance(value, str):
+ r += " \"" + value + "\""
+ else:
+ r += " " + str(value)
+ r += "\n"
+
+ r += "\n#endif\n"
+ return r
+
+
+def get_csr_csv(regions):
+ r = ""
+ for name, origin, busword, obj in regions:
+ if not isinstance(obj, Memory):
+ for csr in obj:
+ nr = (csr.size + busword - 1)//busword
+ r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, origin, nr, "ro" if isinstance(csr, CSRStatus) else "rw")
+ origin += 4*nr
+ return r
--- /dev/null
+from operator import itemgetter
+
+from migen import *
+from migen.bank import csrgen
+from migen.bus import wishbone, csr, wishbone2csr
+
+from misoc import lm32, mor1kx, identifier, timer, uart
+
+
+def mem_decoder(address, start=26, end=29):
+ return lambda a: a[start:end] == ((address >> (start+2)) & (2**(end-start))-1)
+
+
+class SoCCore(Module):
+ csr_map = {
+ "crg": 0, # user
+ "uart_phy": 1, # provided by default (optional)
+ "uart": 2, # provided by default (optional)
+ "identifier": 3, # provided by default (optional)
+ "timer0": 4, # provided by default (optional)
+ "buttons": 5, # user
+ "leds": 6, # user
+ }
+ interrupt_map = {
+ "uart": 0,
+ "timer0": 1,
+ }
+ mem_map = {
+ "rom": 0x00000000, # (default shadow @0x80000000)
+ "sram": 0x10000000, # (default shadow @0x90000000)
+ "main_ram": 0x40000000, # (default shadow @0xc0000000)
+ "csr": 0x60000000, # (default shadow @0xe0000000)
+ }
+ def __init__(self, platform, clk_freq,
+ cpu_type="lm32", cpu_reset_address=0x00000000,
+ integrated_rom_size=0,
+ integrated_sram_size=4096,
+ integrated_main_ram_size=0,
+ shadow_base=0x80000000,
+ with_csr=True, csr_data_width=8, csr_address_width=14,
+ with_uart=True, uart_baudrate=115200,
+ with_identifier=True,
+ with_timer=True):
+ self.platform = platform
+ self.clk_freq = clk_freq
+
+ self.cpu_type = cpu_type
+ if integrated_rom_size:
+ cpu_reset_address = 0
+ self.cpu_reset_address = cpu_reset_address
+
+ self.integrated_rom_size = integrated_rom_size
+ self.integrated_sram_size = integrated_sram_size
+ self.integrated_main_ram_size = integrated_main_ram_size
+
+ self.with_uart = with_uart
+ self.uart_baudrate = uart_baudrate
+
+ self.with_identifier = with_identifier
+
+ self.shadow_base = shadow_base
+
+ self.with_csr = with_csr
+ self.csr_data_width = csr_data_width
+ self.csr_address_width = csr_address_width
+
+ self._memory_regions = [] # list of (name, origin, length)
+ self._csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
+ self._constants = [] # list of (name, value)
+
+ self._wb_masters = []
+ self._wb_slaves = []
+
+ if cpu_type != "none":
+ if cpu_type == "lm32":
+ self.add_cpu_or_bridge(lm32.LM32(platform, self.cpu_reset_address))
+ elif cpu_type == "or1k":
+ self.add_cpu_or_bridge(mor1kx.MOR1KX(platform, self.cpu_reset_address))
+ else:
+ raise ValueError("Unsupported CPU type: {}".format(cpu_type))
+ self.add_wb_master(self.cpu_or_bridge.ibus)
+ self.add_wb_master(self.cpu_or_bridge.dbus)
+
+ if integrated_rom_size:
+ self.submodules.rom = wishbone.SRAM(integrated_rom_size, read_only=True)
+ self.register_rom(self.rom.bus, integrated_rom_size)
+
+ if integrated_sram_size:
+ self.submodules.sram = wishbone.SRAM(integrated_sram_size)
+ self.register_mem("sram", self.mem_map["sram"], self.sram.bus, integrated_sram_size)
+
+ # Note: Main Ram can be used when no external SDRAM is available and use SDRAM mapping.
+ if integrated_main_ram_size:
+ self.submodules.main_ram = wishbone.SRAM(integrated_main_ram_size)
+ self.register_mem("main_ram", self.mem_map["main_ram"], self.main_ram.bus, integrated_main_ram_size)
+
+ if with_csr:
+ self.submodules.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(csr_data_width, csr_address_width))
+ self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone)
+
+ if with_uart:
+ self.submodules.uart_phy = uart.RS232PHY(platform.request("serial"), clk_freq, uart_baudrate)
+ self.submodules.uart = uart.UART(self.uart_phy)
+
+ if with_identifier:
+ platform_id = 0x554E if not hasattr(platform, "identifier") else platform.identifier
+ self.submodules.identifier = identifier.Identifier(platform_id, int(clk_freq))
+
+ if with_timer:
+ self.submodules.timer0 = timer.Timer()
+
+ def add_cpu_or_bridge(self, cpu_or_bridge):
+ if self.finalized:
+ raise FinalizeError
+ if hasattr(self, "cpu_or_bridge"):
+ raise NotImplementedError("More than one CPU is not supported")
+ self.submodules.cpu_or_bridge = cpu_or_bridge
+
+ def init_rom(self, data):
+ self.rom.mem.init = data
+
+ def add_wb_master(self, wbm):
+ if self.finalized:
+ raise FinalizeError
+ self._wb_masters.append(wbm)
+
+ def add_wb_slave(self, address_decoder, interface):
+ if self.finalized:
+ raise FinalizeError
+ self._wb_slaves.append((address_decoder, interface))
+
+ def add_memory_region(self, name, origin, length):
+ def in_this_region(addr):
+ return addr >= origin and addr < origin + length
+ for n, o, l in self._memory_regions:
+ if n == name or in_this_region(o) or in_this_region(o+l-1):
+ raise ValueError("Memory region conflict between {} and {}".format(n, name))
+
+ self._memory_regions.append((name, origin, length))
+
+ def register_mem(self, name, address, interface, size=None):
+ self.add_wb_slave(mem_decoder(address), interface)
+ if size is not None:
+ self.add_memory_region(name, address, size)
+
+ def register_rom(self, interface, rom_size=0xa000):
+ self.add_wb_slave(mem_decoder(self.mem_map["rom"]), interface)
+ self.add_memory_region("rom", self.cpu_reset_address, rom_size)
+
+ def get_memory_regions(self):
+ return self._memory_regions
+
+ def check_csr_region(self, name, origin):
+ for n, o, l, obj in self._csr_regions:
+ if n == name or o == origin:
+ raise ValueError("CSR region conflict between {} and {}".format(n, name))
+
+ def add_csr_region(self, name, origin, busword, obj):
+ self.check_csr_region(name, origin)
+ self._csr_regions.append((name, origin, busword, obj))
+
+ def get_csr_regions(self):
+ return self._csr_regions
+
+ def add_constant(self, name, value=None):
+ self._constants.append((name, value))
+
+ def get_constants(self):
+ r = []
+ for name, interrupt in sorted(self.interrupt_map.items(), key=itemgetter(1)):
+ r.append((name.upper() + "_INTERRUPT", interrupt))
+ r += self._constants
+ return r
+
+ def do_finalize(self):
+ registered_mems = {regions[0] for regions in self._memory_regions}
+ if self.cpu_type != "none":
+ for mem in "rom", "sram":
+ if mem not in registered_mems:
+ raise FinalizeError("CPU needs a {} to be registered with SoC.register_mem()".format(mem))
+
+ # Wishbone
+ self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
+ self._wb_slaves, register=True)
+
+ # CSR
+ if self.with_csr:
+ self.submodules.csrbankarray = csrgen.BankArray(self,
+ lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
+ data_width=self.csr_data_width, address_width=self.csr_address_width)
+ self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses())
+ for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
+ self.add_csr_region(name, (self.mem_map["csr"] + 0x800*mapaddr) | self.shadow_base, self.csr_data_width, csrs)
+ for name, memory, mapaddr, mmap in self.csrbankarray.srams:
+ self.add_csr_region(name + "_" + memory.name_override, (self.mem_map["csr"] + 0x800*mapaddr) | self.shadow_base, self.csr_data_width, memory)
+
+ # Interrupts
+ if hasattr(self.cpu_or_bridge, "interrupt"):
+ for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)):
+ if hasattr(self, k):
+ self.comb += self.cpu_or_bridge.interrupt[v].eq(getattr(self, k).ev.irq)
--- /dev/null
+from migen import *
+from migen.bus import wishbone
+from migen.genlib.record import *
+
+from misoc.mem.sdram.core import SDRAMCore
+from misoc.mem.sdram.core.lasmicon import LASMIconSettings
+from misoc.mem.sdram.core.minicon import MiniconSettings
+from misoc.mem.sdram.frontend import memtest, wishbone2lasmi
+from misoc.integration.soc_core import SoCCore
+
+
+class SoCSDRAM(SoCCore):
+ csr_map = {
+ "sdram": 8,
+ "l2_cache": 9,
+ "memtest_w": 10,
+ "memtest_r": 11
+ }
+ csr_map.update(SoC.csr_map)
+
+ def __init__(self, platform, clk_freq, sdram_controller_settings,
+ **kwargs):
+ SoC.__init__(self, platform, clk_freq, **kwargs)
+ if isinstance(sdram_controller_settings, str):
+ self.sdram_controller_settings = eval(sdram_controller_settings)
+ else:
+ self.sdram_controller_settings = sdram_controller_settings
+ self._sdram_phy_registered = False
+ self._wb_sdram_ifs = []
+ self._wb_sdram = wishbone.Interface()
+
+ def add_wb_sdram_if(self, interface):
+ if self.finalized:
+ raise FinalizeError
+ self._wb_sdram_ifs.append(interface)
+
+ def register_sdram_phy(self, phy):
+ if self._sdram_phy_registered:
+ raise FinalizeError
+ self._sdram_phy_registered = True
+
+ # Core
+ self.submodules.sdram = SDRAMCore(phy,
+ phy.module.geom_settings,
+ phy.module.timing_settings,
+ self.sdram_controller_settings)
+
+ dfi_databits_divisor = 1 if phy.settings.memtype == "SDR" else 2
+ sdram_width = phy.settings.dfi_databits//dfi_databits_divisor
+ main_ram_size = 2**(phy.module.geom_settings.bankbits +
+ phy.module.geom_settings.rowbits +
+ phy.module.geom_settings.colbits)*sdram_width//8
+ # XXX: Limit main_ram_size to 256MB, we should modify mem_map to allow larger memories.
+ main_ram_size = min(main_ram_size, 256*1024*1024)
+ l2_size = self.sdram_controller_settings.l2_size
+ if l2_size:
+ self.add_constant("L2_SIZE", l2_size)
+
+ # add a Wishbone interface to the DRAM
+ wb_sdram = wishbone.Interface()
+ self.add_wb_sdram_if(wb_sdram)
+ self.register_mem("main_ram", self.mem_map["main_ram"], wb_sdram, main_ram_size)
+
+ # LASMICON frontend
+ if isinstance(self.sdram_controller_settings, LASMIconSettings):
+ if self.sdram_controller_settings.with_bandwidth:
+ self.sdram.controller.multiplexer.add_bandwidth()
+
+ if self.sdram_controller_settings.with_memtest:
+ self.submodules.memtest_w = memtest.MemtestWriter(self.sdram.crossbar.get_master())
+ self.submodules.memtest_r = memtest.MemtestReader(self.sdram.crossbar.get_master())
+
+ if l2_size:
+ lasmim = self.sdram.crossbar.get_master()
+ l2_cache = wishbone.Cache(l2_size//4, self._wb_sdram, wishbone.Interface(lasmim.dw))
+ # XXX Vivado ->2015.1 workaround, Vivado is not able to map correctly our L2 cache.
+ # Issue is reported to Xilinx and should be fixed in next releases (2015.2?).
+ # Remove this workaround when fixed by Xilinx.
+ from mibuild.xilinx.vivado import XilinxVivadoToolchain
+ if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
+ from migen.fhdl.simplify import FullMemoryWE
+ self.submodules.l2_cache = FullMemoryWE()(l2_cache)
+ else:
+ self.submodules.l2_cache = l2_cache
+ self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(self.l2_cache.slave, lasmim)
+
+ # MINICON frontend
+ elif isinstance(self.sdram_controller_settings, MiniconSettings):
+ if l2_size:
+ l2_cache = wishbone.Cache(l2_size//4, self._wb_sdram, self.sdram.controller.bus)
+ # XXX Vivado ->2015.1 workaround, Vivado is not able to map correctly our L2 cache.
+ # Issue is reported to Xilinx and should be fixed in next releases (2015.2?).
+ # Remove this workaround when fixed by Xilinx.
+ from mibuild.xilinx.vivado import XilinxVivadoToolchain
+ if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
+ from migen.fhdl.simplify import FullMemoryWE
+ self.submodules.l2_cache = FullMemoryWE()(l2_cache)
+ else:
+ self.submodules.l2_cache = l2_cache
+ else:
+ self.submodules.converter = wishbone.Converter(self._wb_sdram, self.sdram.controller.bus)
+
+ def do_finalize(self):
+ if not self.integrated_main_ram_size:
+ if not self._sdram_phy_registered:
+ raise FinalizeError("Need to call SDRAMSoC.register_sdram_phy()")
+
+ # arbitrate wishbone interfaces to the DRAM
+ self.submodules.wb_sdram_con = wishbone.Arbiter(self._wb_sdram_ifs,
+ self._wb_sdram)
+ SoC.do_finalize(self)
--- /dev/null
+Unless otherwise noted, LiteEth is copyright (C) 2015 Florent Kermarrec.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Other authors retain ownership of their contributions. If a submission can
+reasonably be considered independently copyrightable, it's yours and we
+encourage you to claim it with appropriate copyright notices. This submission
+then falls under the "otherwise noted" category. All submissions are strongly
+encouraged to use the two-clause BSD license reproduced above.
--- /dev/null
+ __ _ __ ______ __ __ ____ _
+ / / (_) /____ / __/ /_/ / / |/ (_)__ (_)
+ / /__/ / __/ -_) _// __/ _ \/ /|_/ / / _ \/ /
+ /____/_/\__/\__/___/\__/_//_/_/ /_/_/_//_/_/
+
+ Copyright 2012-2015 / EnjoyDigital / M-Labs Ltd
+
+ A small footprint and configurable minimal Ethernet core
+ powered by Migen
+
+[> Intro
+---------
+LiteEthMini is a subset of LiteEth (https://github.com/enjoy-digital/liteeth)
+intended to be used with a CPU and a software stack.
+
+[> Features
+-----------
+- Ethernet MAC with various various PHYs (GMII, MII, RGMII, Loopback)
+- SRAM storage and wishbone interface
+
+[> Possible improvements
+-------------------------
+- add DMA interface to MAC
+- add SGMII PHY
+- ... See below Support and consulting :)
+
+If you want to support these features, please contact us at florent [AT]
+enjoy-digital.fr. You can also contact our partner on the public mailing list
+devel [AT] lists.m-labs.hk.
+
+[> License
+-----------
+LiteEthMini is released under the very permissive two-clause BSD license. Under
+the terms of this license, you are authorized to use LiteEthMini for closed-source
+proprietary designs.
+Even though we do not require you to do so, those things are awesome, so please
+do them if possible:
+ - tell us that you are using LiteEthMini
+ - cite LiteEthMini in publications related to research it has helped
+ - send us feedback and suggestions for improvements
+ - send us bug reports when something goes wrong
+ - send us the modifications and improvements you have done to LiteEthMini.
+
+[> Support and consulting
+--------------------------
+We love open-source hardware and like sharing our designs with others.
+
+LiteEthMini is mainly developed and maintained by EnjoyDigital.
+
+If you would like to know more about LiteEthMini or if you are already a happy
+user and would like to extend it for your needs, EnjoyDigital can provide standard
+commercial support as well as consulting services.
+
+So feel free to contact us, we'd love to work with you! (and eventually shorten
+the list of the possible improvements :)
+
+[> Contact
+E-mail: florent [AT] enjoy-digital.fr
\ No newline at end of file
--- /dev/null
+import math
+from collections import OrderedDict
+
+from migen import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+from migen.genlib.record import *
+from migen.genlib.fsm import FSM, NextState
+from migen.genlib.misc import chooser, reverse_bytes, FlipFlop, Counter, WaitTimer
+from migen.flow.actor import *
+from migen.actorlib.structuring import Converter, Pipeline
+from migen.actorlib.fifo import SyncFIFO, AsyncFIFO
+from migen.actorlib.packet import *
+from migen.bank.description import *
+
+class Port:
+ def connect(self, port):
+ r = [
+ Record.connect(self.source, port.sink),
+ Record.connect(port.source, self.sink)
+ ]
+ return r
+
+eth_mtu = 1532
+eth_min_len = 46
+eth_interpacket_gap = 12
+eth_preamble = 0xD555555555555555
+buffer_depth = 2**log2_int(eth_mtu, need_pow2=False)
+
+def eth_phy_description(dw):
+ payload_layout = [
+ ("data", dw),
+ ("last_be", dw//8),
+ ("error", dw//8)
+ ]
+ return EndpointDescription(payload_layout, packetized=True)
+
+
+def eth_mac_description(dw):
+ payload_layout = mac_header.get_layout() + [
+ ("data", dw),
+ ("last_be", dw//8),
+ ("error", dw//8)
+ ]
+ return EndpointDescription(payload_layout, packetized=True)
--- /dev/null
+from misoc.com.liteethmini.common import *
+from misoc.com.liteethmini.mac.core import LiteEthMACCore
+from misoc.com.liteethmini.mac.frontend.wishbone import LiteEthMACWishboneInterface
+
+
+class LiteEthMAC(Module, AutoCSR):
+ def __init__(self, phy, dw,
+ interface="wishbone",
+ endianness="big",
+ with_preamble_crc=True):
+ self.submodules.core = LiteEthMACCore(phy, dw, endianness, with_preamble_crc)
+ self.csrs = []
+ if interface == "wishbone":
+ self.submodules.interface = LiteEthMACWishboneInterface(dw, 2, 2)
+ self.comb += Port.connect(self.interface, self.core)
+ self.ev, self.bus = self.interface.sram.ev, self.interface.bus
+ self.csrs = self.interface.get_csrs() + self.core.get_csrs()
+ else:
+ raise NotImplementedError
+
+ def get_csrs(self):
+ return self.csrs
--- /dev/null
+from misoc.com.liteethmini.common import *
+from misoc.com.liteethmini.mac.core import gap, preamble, crc, padding, last_be
+from misoc.com.liteethmini.phy.sim import LiteEthPHYSim
+from misoc.com.liteethmini.phy.mii import LiteEthPHYMII
+
+
+class LiteEthMACCore(Module, AutoCSR):
+ def __init__(self, phy, dw, endianness="big",
+ with_preamble_crc=True,
+ with_padding=True):
+ if dw < phy.dw:
+ raise ValueError("Core data width({}) must be larger than PHY data width({})".format(dw, phy.dw))
+
+ rx_pipeline = [phy]
+ tx_pipeline = [phy]
+
+ # Interpacket gap
+ tx_gap_inserter = gap.LiteEthMACGap(phy.dw)
+ rx_gap_checker = gap.LiteEthMACGap(phy.dw, ack_on_gap=True)
+ self.submodules += RenameClockDomains(tx_gap_inserter, "eth_tx")
+ self.submodules += RenameClockDomains(rx_gap_checker, "eth_rx")
+
+ tx_pipeline += [tx_gap_inserter]
+ rx_pipeline += [rx_gap_checker]
+
+ # Preamble / CRC
+ if isinstance(phy, LiteEthPHYSim):
+ # In simulation, avoid CRC/Preamble to enable direct connection
+ # to the Ethernet tap.
+ self._preamble_crc = CSRStatus(reset=1)
+ elif with_preamble_crc:
+ self._preamble_crc = CSRStatus(reset=1)
+ # Preamble insert/check
+ preamble_inserter = preamble.LiteEthMACPreambleInserter(phy.dw)
+ preamble_checker = preamble.LiteEthMACPreambleChecker(phy.dw)
+ self.submodules += RenameClockDomains(preamble_inserter, "eth_tx")
+ self.submodules += RenameClockDomains(preamble_checker, "eth_rx")
+
+ # CRC insert/check
+ crc32_inserter = crc.LiteEthMACCRC32Inserter(eth_phy_description(phy.dw))
+ crc32_checker = crc.LiteEthMACCRC32Checker(eth_phy_description(phy.dw))
+ self.submodules += RenameClockDomains(crc32_inserter, "eth_tx")
+ self.submodules += RenameClockDomains(crc32_checker, "eth_rx")
+
+ tx_pipeline += [preamble_inserter, crc32_inserter]
+ rx_pipeline += [preamble_checker, crc32_checker]
+
+ # Padding
+ if with_padding:
+ padding_inserter = padding.LiteEthMACPaddingInserter(phy.dw, 60)
+ padding_checker = padding.LiteEthMACPaddingChecker(phy.dw, 60)
+ self.submodules += RenameClockDomains(padding_inserter, "eth_tx")
+ self.submodules += RenameClockDomains(padding_checker, "eth_rx")
+
+ tx_pipeline += [padding_inserter]
+ rx_pipeline += [padding_checker]
+
+ # Delimiters
+ if dw != 8:
+ tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw)
+ rx_last_be = last_be.LiteEthMACRXLastBE(phy.dw)
+ self.submodules += RenameClockDomains(tx_last_be, "eth_tx")
+ self.submodules += RenameClockDomains(rx_last_be, "eth_rx")
+
+ tx_pipeline += [tx_last_be]
+ rx_pipeline += [rx_last_be]
+
+ # Converters
+ if dw != phy.dw:
+ reverse = endianness == "big"
+ tx_converter = Converter(eth_phy_description(dw),
+ eth_phy_description(phy.dw),
+ reverse=reverse)
+ rx_converter = Converter(eth_phy_description(phy.dw),
+ eth_phy_description(dw),
+ reverse=reverse)
+ self.submodules += RenameClockDomains(tx_converter, "eth_tx")
+ self.submodules += RenameClockDomains(rx_converter, "eth_rx")
+
+ tx_pipeline += [tx_converter]
+ rx_pipeline += [rx_converter]
+
+ # Cross Domain Crossing
+ if isinstance(phy, LiteEthPHYMII):
+ fifo_depth = 8
+ else:
+ fifo_depth = 64
+ tx_cdc = AsyncFIFO(eth_phy_description(dw), fifo_depth)
+ rx_cdc = AsyncFIFO(eth_phy_description(dw), fifo_depth)
+ self.submodules += RenameClockDomains(tx_cdc, {"write": "sys", "read": "eth_tx"})
+ self.submodules += RenameClockDomains(rx_cdc, {"write": "eth_rx", "read": "sys"})
+
+ tx_pipeline += [tx_cdc]
+ rx_pipeline += [rx_cdc]
+
+ # Graph
+ self.submodules.tx_pipeline = Pipeline(*reversed(tx_pipeline))
+ self.submodules.rx_pipeline = Pipeline(*rx_pipeline)
+
+ self.sink, self.source = self.tx_pipeline.sink, self.rx_pipeline.source
--- /dev/null
+from misoc.com.liteethmini.common import *
+
+
+class LiteEthMACCRCEngine(Module):
+ """Cyclic Redundancy Check Engine
+
+ Compute next CRC value from last CRC value and data input using
+ an optimized asynchronous LFSR.
+
+ Parameters
+ ----------
+ data_width : int
+ Width of the data bus.
+ width : int
+ Width of the CRC.
+ polynom : int
+ Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
+
+ Attributes
+ ----------
+ data : in
+ Data input.
+ last : in
+ last CRC value.
+ next :
+ next CRC value.
+ """
+ def __init__(self, data_width, width, polynom):
+ self.data = Signal(data_width)
+ self.last = Signal(width)
+ self.next = Signal(width)
+
+ # # #
+
+ def _optimize_eq(l):
+ """
+ Replace even numbers of XORs in the equation
+ with an equivalent XOR
+ """
+ d = OrderedDict()
+ for e in l:
+ if e in d:
+ d[e] += 1
+ else:
+ d[e] = 1
+ r = []
+ for key, value in d.items():
+ if value%2 != 0:
+ r.append(key)
+ return r
+
+ # compute and optimize CRC's LFSR
+ curval = [[("state", i)] for i in range(width)]
+ for i in range(data_width):
+ feedback = curval.pop() + [("din", i)]
+ for j in range(width-1):
+ if (polynom & (1<<(j+1))):
+ curval[j] += feedback
+ curval[j] = _optimize_eq(curval[j])
+ curval.insert(0, feedback)
+
+ # implement logic
+ for i in range(width):
+ xors = []
+ for t, n in curval[i]:
+ if t == "state":
+ xors += [self.last[n]]
+ elif t == "din":
+ xors += [self.data[n]]
+ self.comb += self.next[i].eq(optree("^", xors))
+
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class LiteEthMACCRC32(Module):
+ """IEEE 802.3 CRC
+
+ Implement an IEEE 802.3 CRC generator/checker.
+
+ Parameters
+ ----------
+ data_width : int
+ Width of the data bus.
+
+ Attributes
+ ----------
+ d : in
+ Data input.
+ value : out
+ CRC value (used for generator).
+ error : out
+ CRC error (used for checker).
+ """
+ width = 32
+ polynom = 0x04C11DB7
+ init = 2**width-1
+ check = 0xC704DD7B
+ def __init__(self, data_width):
+ self.data = Signal(data_width)
+ self.value = Signal(self.width)
+ self.error = Signal()
+
+ # # #
+
+ self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom)
+ reg = Signal(self.width, reset=self.init)
+ self.sync += reg.eq(self.engine.next)
+ self.comb += [
+ self.engine.data.eq(self.data),
+ self.engine.last.eq(reg),
+
+ self.value.eq(~reg[::-1]),
+ self.error.eq(self.engine.next != self.check)
+ ]
+
+
+class LiteEthMACCRCInserter(Module):
+ """CRC Inserter
+
+ Append a CRC at the end of each packet.
+
+ Parameters
+ ----------
+ description : description
+ description of the dataflow.
+
+ Attributes
+ ----------
+ sink : in
+ Packets input without CRC.
+ source : out
+ Packets output with CRC.
+ """
+ def __init__(self, crc_class, description):
+ self.sink = sink = Sink(description)
+ self.source = source = Source(description)
+ self.busy = Signal()
+
+ # # #
+
+ dw = flen(sink.data)
+ crc = crc_class(dw)
+ fsm = FSM(reset_state="IDLE")
+ self.submodules += crc, fsm
+
+ fsm.act("IDLE",
+ crc.reset.eq(1),
+ sink.ack.eq(1),
+ If(sink.stb & sink.sop,
+ sink.ack.eq(0),
+ NextState("COPY"),
+ )
+ )
+ fsm.act("COPY",
+ crc.ce.eq(sink.stb & source.ack),
+ crc.data.eq(sink.data),
+ Record.connect(sink, source),
+ source.eop.eq(0),
+ If(sink.stb & sink.eop & source.ack,
+ NextState("INSERT"),
+ )
+ )
+ ratio = crc.width//dw
+ if ratio > 1:
+ cnt = Signal(max=ratio, reset=ratio-1)
+ cnt_done = Signal()
+ fsm.act("INSERT",
+ source.stb.eq(1),
+ chooser(crc.value, cnt, source.data, reverse=True),
+ If(cnt_done,
+ source.eop.eq(1),
+ If(source.ack, NextState("IDLE"))
+ )
+ )
+ self.comb += cnt_done.eq(cnt == 0)
+ self.sync += \
+ If(fsm.ongoing("IDLE"),
+ cnt.eq(cnt.reset)
+ ).Elif(fsm.ongoing("INSERT") & ~cnt_done,
+ cnt.eq(cnt - source.ack)
+ )
+ else:
+ fsm.act("INSERT",
+ source.stb.eq(1),
+ source.eop.eq(1),
+ source.data.eq(crc.value),
+ If(source.ack, NextState("IDLE"))
+ )
+ self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
+
+
+class LiteEthMACCRC32Inserter(LiteEthMACCRCInserter):
+ def __init__(self, description):
+ LiteEthMACCRCInserter.__init__(self, LiteEthMACCRC32, description)
+
+
+class LiteEthMACCRCChecker(Module):
+ """CRC Checker
+
+ Check CRC at the end of each packet.
+
+ Parameters
+ ----------
+ description : description
+ description of the dataflow.
+
+ Attributes
+ ----------
+ sink : in
+ Packets input with CRC.
+ source : out
+ Packets output without CRC and "error" set to 0
+ on eop when CRC OK / set to 1 when CRC KO.
+ """
+ def __init__(self, crc_class, description):
+ self.sink = sink = Sink(description)
+ self.source = source = Source(description)
+ self.busy = Signal()
+
+ # # #
+
+ dw = flen(sink.data)
+ crc = crc_class(dw)
+ self.submodules += crc
+ ratio = crc.width//dw
+
+ error = Signal()
+ fifo = InsertReset(SyncFIFO(description, ratio + 1))
+ self.submodules += fifo
+
+ fsm = FSM(reset_state="RESET")
+ self.submodules += fsm
+
+ fifo_in = Signal()
+ fifo_out = Signal()
+ fifo_full = Signal()
+
+ self.comb += [
+ fifo_full.eq(fifo.fifo.level == ratio),
+ fifo_in.eq(sink.stb & (~fifo_full | fifo_out)),
+ fifo_out.eq(source.stb & source.ack),
+
+ Record.connect(sink, fifo.sink),
+ fifo.sink.stb.eq(fifo_in),
+ self.sink.ack.eq(fifo_in),
+
+ source.stb.eq(sink.stb & fifo_full),
+ source.sop.eq(fifo.source.sop),
+ source.eop.eq(sink.eop),
+ fifo.source.ack.eq(fifo_out),
+ source.payload.eq(fifo.source.payload),
+
+ source.error.eq(sink.error | crc.error),
+ ]
+
+ fsm.act("RESET",
+ crc.reset.eq(1),
+ fifo.reset.eq(1),
+ NextState("IDLE"),
+ )
+ self.comb += crc.data.eq(sink.data)
+ fsm.act("IDLE",
+ If(sink.stb & sink.sop & sink.ack,
+ crc.ce.eq(1),
+ NextState("COPY")
+ )
+ )
+ fsm.act("COPY",
+ If(sink.stb & sink.ack,
+ crc.ce.eq(1),
+ If(sink.eop,
+ NextState("RESET")
+ )
+ )
+ )
+ self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
+
+
+class LiteEthMACCRC32Checker(LiteEthMACCRCChecker):
+ def __init__(self, description):
+ LiteEthMACCRCChecker.__init__(self, LiteEthMACCRC32, description)
--- /dev/null
+from misoc.com.liteethmini.common import *
+
+class LiteEthMACGap(Module):
+ def __init__(self, dw, ack_on_gap=False):
+ self.sink = sink = Sink(eth_phy_description(dw))
+ self.source = source = Source(eth_phy_description(dw))
+
+ # # #
+
+ gap = math.ceil(eth_interpacket_gap/(dw//8))
+ self.submodules.counter = counter = Counter(max=gap)
+
+ self.submodules.fsm = fsm = FSM(reset_state="COPY")
+ fsm.act("COPY",
+ counter.reset.eq(1),
+ Record.connect(sink, source),
+ If(sink.stb & sink.eop & sink.ack,
+ NextState("GAP")
+ )
+ )
+ fsm.act("GAP",
+ counter.ce.eq(1),
+ sink.ack.eq(int(ack_on_gap)),
+ If(counter.value == (gap-1),
+ NextState("COPY")
+ )
+ )
--- /dev/null
+from misoc.com.liteethmini.common import *
+
+
+class LiteEthMACTXLastBE(Module):
+ def __init__(self, dw):
+ self.sink = sink = Sink(eth_phy_description(dw))
+ self.source = source = Source(eth_phy_description(dw))
+
+ # # #
+
+ ongoing = Signal()
+ self.sync += \
+ If(sink.stb & sink.ack,
+ If(sink.sop,
+ ongoing.eq(1)
+ ).Elif(sink.last_be,
+ ongoing.eq(0)
+ )
+ )
+ self.comb += [
+ source.stb.eq(sink.stb & (sink.sop | ongoing)),
+ source.sop.eq(sink.sop),
+ source.eop.eq(sink.last_be),
+ source.data.eq(sink.data),
+ sink.ack.eq(source.ack)
+ ]
+
+
+class LiteEthMACRXLastBE(Module):
+ def __init__(self, dw):
+ self.sink = sink = Sink(eth_phy_description(dw))
+ self.source = source = Source(eth_phy_description(dw))
+
+ # # #
+
+ self.comb += [
+ source.stb.eq(sink.stb),
+ source.sop.eq(sink.sop),
+ source.eop.eq(sink.eop),
+ source.data.eq(sink.data),
+ source.last_be.eq(sink.eop),
+ sink.ack.eq(source.ack)
+ ]
--- /dev/null
+from misoc.com.liteethmini.common import *
+
+
+class LiteEthMACPaddingInserter(Module):
+ def __init__(self, dw, padding):
+ self.sink = sink = Sink(eth_phy_description(dw))
+ self.source = source = Source(eth_phy_description(dw))
+
+ # # #
+
+ padding_limit = math.ceil(padding/(dw/8))-1
+
+ self.submodules.counter = counter = Counter(16, reset=1)
+ counter_done = Signal()
+ self.comb += [
+ counter.reset.eq(sink.stb & sink.sop & sink.ack),
+ counter.ce.eq(source.stb & source.ack),
+ counter_done.eq(counter.value >= padding_limit),
+ ]
+
+ self.submodules.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ Record.connect(sink, source),
+ If(source.stb & source.ack,
+ counter.ce.eq(1),
+ If(sink.eop,
+ If(~counter_done,
+ source.eop.eq(0),
+ NextState("PADDING")
+ )
+ )
+ )
+ )
+ fsm.act("PADDING",
+ source.stb.eq(1),
+ source.eop.eq(counter_done),
+ source.data.eq(0),
+ If(source.ack,
+ If(counter_done,
+ NextState("IDLE")
+ )
+ )
+ )
+
+
+class LiteEthMACPaddingChecker(Module):
+ def __init__(self, dw, packet_min_length):
+ self.sink = sink = Sink(eth_phy_description(dw))
+ self.source = source = Source(eth_phy_description(dw))
+
+ # # #
+
+ # XXX see if we should drop the packet when
+ # payload size < minimum ethernet payload size
+ self.comb += Record.connect(sink, source)
+
--- /dev/null
+from misoc.com.liteethmini.common import *
+
+
+class LiteEthMACPreambleInserter(Module):
+ def __init__(self, dw):
+ self.sink = Sink(eth_phy_description(dw))
+ self.source = Source(eth_phy_description(dw))
+
+ # # #
+
+ preamble = Signal(64, reset=eth_preamble)
+ cnt_max = (64//dw)-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.data),
+ If(cnt == cnt_max,
+ If(self.source.ack, NextState("COPY"))
+ ).Else(
+ inc_cnt.eq(self.source.ack)
+ )
+ )
+
+ self.comb += [
+ self.source.data.eq(self.sink.data),
+ self.source.last_be.eq(self.sink.last_be)
+ ]
+ fsm.act("COPY",
+ Record.connect(self.sink, self.source, leave_out=set(["data", "last_be"])),
+ self.source.sop.eq(0),
+
+ If(self.sink.stb & self.sink.eop & self.source.ack,
+ NextState("IDLE"),
+ )
+ )
+
+
+class LiteEthMACPreambleChecker(Module):
+ def __init__(self, dw):
+ self.sink = Sink(eth_phy_description(dw))
+ self.source = Source(eth_phy_description(dw))
+
+ # # #
+
+ preamble = Signal(64, reset=eth_preamble)
+ cnt_max = (64//dw) - 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(dw)
+ match = Signal()
+ self.comb += [
+ chooser(preamble, cnt, ref),
+ match.eq(self.sink.data == 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)
+ )
+ )
+ )
+ self.comb += [
+ self.source.data.eq(self.sink.data),
+ self.source.last_be.eq(self.sink.last_be)
+ ]
+ fsm.act("COPY",
+ Record.connect(self.sink, self.source, leave_out=set(["data", "last_be"])),
+ 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"),
+ )
+ )
--- /dev/null
+from misoc.com.liteethmini.common import *
+
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+
+
+class LiteEthMACSRAMWriter(Module, AutoCSR):
+ def __init__(self, dw, depth, nslots=2):
+ self.sink = sink = Sink(eth_phy_description(dw))
+ 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
+ increment = Signal(3)
+ self.comb += \
+ If(sink.last_be[3],
+ increment.eq(1)
+ ).Elif(sink.last_be[2],
+ increment.eq(2)
+ ).Elif(sink.last_be[1],
+ increment.eq(3)
+ ).Else(
+ increment.eq(4)
+ )
+ counter = Counter(lengthbits, increment=increment)
+ self.submodules += counter
+
+ # slot computation
+ slot = Counter(slotbits)
+ self.submodules += slot
+
+ ongoing = 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",
+ If(sink.stb & sink.sop,
+ If(fifo.sink.ack,
+ ongoing.eq(1),
+ counter.ce.eq(1),
+ NextState("WRITE")
+ )
+ )
+ )
+ fsm.act("WRITE",
+ counter.ce.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",
+ counter.reset.eq(1),
+ NextState("IDLE")
+ )
+ self.comb += [
+ fifo.sink.slot.eq(slot.value),
+ fifo.sink.length.eq(counter.value)
+ ]
+ fsm.act("TERMINATE",
+ counter.reset.eq(1),
+ slot.ce.eq(1),
+ fifo.sink.stb.eq(1),
+ NextState("IDLE")
+ )
+ self.comb += [
+ fifo.source.ack.eq(self.ev.available.clear),
+ self.ev.available.trigger.eq(fifo.source.stb),
+ self._slot.status.eq(fifo.source.slot),
+ self._length.status.eq(fifo.source.length),
+ ]
+
+ # memory
+ mems = [None]*nslots
+ ports = [None]*nslots
+ for n in range(nslots):
+ mems[n] = Memory(dw, 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(counter.value[2:]),
+ ports[n].dat_w.eq(sink.data),
+ If(sink.stb & ongoing,
+ ports[n].we.eq(0xf)
+ )
+ ]
+ self.comb += Case(slot.value, cases)
+
+
+class LiteEthMACSRAMReader(Module, AutoCSR):
+ def __init__(self, dw, depth, nslots=2):
+ self.source = source = Source(eth_phy_description(dw))
+
+ 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.sink.stb.eq(self._start.re),
+ fifo.sink.slot.eq(self._slot.storage),
+ fifo.sink.length.eq(self._length.storage),
+ self._ready.status.eq(fifo.sink.ack)
+ ]
+
+ # length computation
+ self.submodules.counter = counter = Counter(lengthbits, increment=4)
+
+ # fsm
+ first = Signal()
+ last = Signal()
+ last_d = Signal()
+
+ fsm = FSM(reset_state="IDLE")
+ self.submodules += fsm
+
+ fsm.act("IDLE",
+ counter.reset.eq(1),
+ If(fifo.source.stb,
+ NextState("CHECK")
+ )
+ )
+ fsm.act("CHECK",
+ If(~last_d,
+ NextState("SEND"),
+ ).Else(
+ NextState("END"),
+ )
+ )
+ length_lsb = fifo.source.length[0:2]
+ self.comb += [
+ 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)
+ )
+ )
+ ]
+ fsm.act("SEND",
+ source.stb.eq(1),
+ source.sop.eq(first),
+ source.eop.eq(last),
+ If(source.ack,
+ counter.ce.eq(~last),
+ NextState("CHECK")
+ )
+ )
+ fsm.act("END",
+ fifo.source.ack.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((counter.value + 4) >= fifo.source.length)
+ self.sync += last_d.eq(last)
+
+ # memory
+ rd_slot = fifo.source.slot
+
+ mems = [None]*nslots
+ ports = [None]*nslots
+ for n in range(nslots):
+ mems[n] = Memory(dw, 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(counter.value[2:])
+ cases[n] = [source.data.eq(port.dat_r)]
+ self.comb += Case(rd_slot, cases)
+
+
+class LiteEthMACSRAM(Module, AutoCSR):
+ def __init__(self, dw, depth, nrxslots, ntxslots):
+ self.submodules.writer = LiteEthMACSRAMWriter(dw, depth, nrxslots)
+ self.submodules.reader = LiteEthMACSRAMReader(dw, depth, ntxslots)
+ self.submodules.ev = SharedIRQ(self.writer.ev, self.reader.ev)
+ self.sink, self.source = self.writer.sink, self.reader.source
--- /dev/null
+from misoc.com.liteethmini.common import *
+from misoc.com.liteethmini.mac.frontend import sram
+
+from migen.bus import wishbone
+from migen.fhdl.simplify import FullMemoryWE
+
+
+class LiteEthMACWishboneInterface(Module, AutoCSR):
+ def __init__(self, dw, nrxslots=2, ntxslots=2):
+ self.sink = Sink(eth_phy_description(dw))
+ self.source = Source(eth_phy_description(dw))
+ self.bus = wishbone.Interface()
+
+ # # #
+
+ # storage in SRAM
+ sram_depth = buffer_depth//(dw//8)
+ self.submodules.sram = sram.LiteEthMACSRAM(dw, sram_depth, nrxslots, ntxslots)
+ self.comb += [
+ Record.connect(self.sink, self.sram.sink),
+ Record.connect(self.sram.source, self.source)
+ ]
+
+ # Wishbone interface
+ wb_rx_sram_ifs = [wishbone.SRAM(self.sram.writer.mems[n], read_only=True)
+ for n in range(nrxslots)]
+ # TODO: FullMemoryWE should move to Mibuild
+ 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
--- /dev/null
+from misoc.com.liteethmini.common import *
+
+
+def LiteEthPHY(clock_pads, pads, clk_freq=None, **kwargs):
+ # Autodetect PHY
+ if hasattr(pads, "source_stb"):
+ # This is a simulation PHY
+ from misoc.com.liteethmini.phy.sim import LiteEthPHYSim
+ return LiteEthPHYSim(pads)
+ elif hasattr(clock_pads, "gtx") and flen(pads.tx_data) == 8:
+ if hasattr(clock_pads, "tx"):
+ # This is a 10/100/1G PHY
+ from misoc.com.liteethmini.phy.gmii_mii import LiteEthPHYGMIIMII
+ return LiteEthPHYGMIIMII(clock_pads, pads, clk_freq=clk_freq, **kwargs)
+ else:
+ # This is a pure 1G PHY
+ from misoc.com.liteethmini.phy.gmii import LiteEthPHYGMII
+ return LiteEthPHYGMII(clock_pads, pads, **kwargs)
+ elif hasattr(pads, "rx_ctl"):
+ # This is a 10/100/1G RGMII PHY
+ raise ValueError("RGMII PHYs are specific to vendors (for now), use direct instantiation")
+ elif flen(pads.tx_data) == 4:
+ # This is a MII PHY
+ from misoc.com.liteethmini.phy.mii import LiteEthPHYMII
+ return LiteEthPHYMII(clock_pads, pads, **kwargs)
+ else:
+ raise ValueError("Unable to autodetect PHY from platform file, use direct instantiation")
--- /dev/null
+from migen.genlib.io import DDROutput
+
+from misoc.com.liteethmini.common import *
+
+
+class LiteEthPHYGMIITX(Module):
+ def __init__(self, pads, pads_register=True):
+ self.sink = sink = Sink(eth_phy_description(8))
+
+ # # #
+
+ if hasattr(pads, "tx_er"):
+ self.sync += pads.tx_er.eq(0)
+ pads_eq = [
+ pads.tx_en.eq(sink.stb),
+ pads.tx_data.eq(sink.data)
+ ]
+ if pads_register:
+ self.sync += pads_eq
+ else:
+ self.comb += pads_eq
+ self.comb += sink.ack.eq(1)
+
+
+class LiteEthPHYGMIIRX(Module):
+ def __init__(self, pads):
+ self.source = source = Source(eth_phy_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.data.eq(pads.rx_data)
+ ]
+ self.comb += source.eop.eq(eop)
+
+
+class LiteEthPHYGMIICRG(Module, AutoCSR):
+ def __init__(self, clock_pads, pads, with_hw_init_reset, mii_mode=0):
+ self._reset = CSRStorage()
+
+ # # #
+
+ self.clock_domains.cd_eth_rx = ClockDomain()
+ self.clock_domains.cd_eth_tx = ClockDomain()
+
+ # RX : Let the synthesis tool insert the appropriate clock buffer
+ self.comb += self.cd_eth_rx.clk.eq(clock_pads.rx)
+
+ # TX : GMII: Drive clock_pads.gtx, clock_pads.tx unused
+ # MII: Use PHY clock_pads.tx as eth_tx_clk, do not drive clock_pads.gtx
+ self.specials += DDROutput(1, mii_mode, clock_pads.gtx, ClockSignal("eth_tx"))
+ # XXX Xilinx specific, replace BUFGMUX with a generic clock buffer?
+ self.specials += Instance("BUFGMUX",
+ i_I0=self.cd_eth_rx.clk,
+ i_I1=clock_pads.tx,
+ i_S=mii_mode,
+ o_O=self.cd_eth_tx.clk)
+
+ if with_hw_init_reset:
+ reset = Signal()
+ counter_done = Signal()
+ self.submodules.counter = counter = Counter(max=512)
+ self.comb += [
+ counter_done.eq(counter.value == 256),
+ counter.ce.eq(~counter_done),
+ reset.eq(~counter_done | self._reset.storage)
+ ]
+ else:
+ 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 LiteEthPHYGMII(Module, AutoCSR):
+ def __init__(self, clock_pads, pads, with_hw_init_reset=True):
+ self.dw = 8
+ self.submodules.crg = LiteEthPHYGMIICRG(clock_pads,
+ pads,
+ with_hw_init_reset)
+ self.submodules.tx = RenameClockDomains(LiteEthPHYGMIITX(pads),
+ "eth_tx")
+ self.submodules.rx = RenameClockDomains(LiteEthPHYGMIIRX(pads),
+ "eth_rx")
+ self.sink, self.source = self.tx.sink, self.rx.source
--- /dev/null
+from migen.genlib.io import DDROutput
+from migen.flow.plumbing import Multiplexer, Demultiplexer
+from migen.genlib.cdc import PulseSynchronizer
+
+from misoc.com.liteethmini.common import *
+
+from misoc.com.liteethmini.phy.gmii import LiteEthPHYGMIICRG
+from misoc.com.liteethmini.phy.mii import LiteEthPHYMIITX, LiteEthPHYMIIRX
+from misoc.com.liteethmini.phy.gmii import LiteEthPHYGMIITX, LiteEthPHYGMIIRX
+
+modes = {
+ "GMII": 0,
+ "MII": 1
+}
+
+tx_pads_layout = [("tx_er", 1), ("tx_en", 1), ("tx_data", 8)]
+rx_pads_layout = [("rx_er", 1), ("dv", 1), ("rx_data", 8)]
+
+
+class LiteEthPHYGMIIMIITX(Module):
+ def __init__(self, pads, mode):
+ self.sink = sink = Sink(eth_phy_description(8))
+
+ # # #
+
+ gmii_tx_pads = Record(tx_pads_layout)
+ gmii_tx = LiteEthPHYGMIITX(gmii_tx_pads, pads_register=False)
+ self.submodules += gmii_tx
+
+ mii_tx_pads = Record(tx_pads_layout)
+ mii_tx = LiteEthPHYMIITX(mii_tx_pads, pads_register=False)
+ self.submodules += mii_tx
+
+ demux = Demultiplexer(eth_phy_description(8), 2)
+ self.submodules += demux
+ self.comb += [
+ demux.sel.eq(mode == modes["MII"]),
+ Record.connect(sink, demux.sink),
+ Record.connect(demux.source0, gmii_tx.sink),
+ Record.connect(demux.source1, mii_tx.sink),
+ ]
+
+ if hasattr(pads, "tx_er"):
+ self.comb += pads.tx_er.eq(0)
+ self.sync += [
+ If(mode == modes["MII"],
+ pads.tx_en.eq(mii_tx_pads.tx_en),
+ pads.tx_data.eq(mii_tx_pads.tx_data),
+ ).Else(
+ pads.tx_en.eq(gmii_tx_pads.tx_en),
+ pads.tx_data.eq(gmii_tx_pads.tx_data),
+ )
+ ]
+
+
+class LiteEthPHYGMIIMIIRX(Module):
+ def __init__(self, pads, mode):
+ self.source = source = Source(eth_phy_description(8))
+
+ # # #
+
+ pads_d = Record(rx_pads_layout)
+ self.sync += [
+ pads_d.dv.eq(pads.dv),
+ pads_d.rx_data.eq(pads.rx_data)
+ ]
+
+ gmii_rx = LiteEthPHYGMIIRX(pads_d)
+ self.submodules += gmii_rx
+
+ mii_rx = LiteEthPHYMIIRX(pads_d)
+ self.submodules += mii_rx
+
+ mux = Multiplexer(eth_phy_description(8), 2)
+ self.submodules += mux
+ self.comb += [
+ mux.sel.eq(mode == modes["MII"]),
+ Record.connect(gmii_rx.source, mux.sink0),
+ Record.connect(mii_rx.source, mux.sink1),
+ Record.connect(mux.source, source)
+ ]
+
+
+class LiteEthGMIIMIIModeDetection(Module, AutoCSR):
+ def __init__(self, clk_freq):
+ self.mode = Signal()
+ self._mode = CSRStatus()
+
+ # # #
+
+ mode = Signal()
+ update_mode = Signal()
+ self.sync += \
+ If(update_mode,
+ self.mode.eq(mode)
+ )
+ self.comb += self._mode.status.eq(self.mode)
+
+ # Principle:
+ # sys_clk >= 125MHz
+ # eth_rx <= 125Mhz
+ # We generate ticks every 1024 clock cycles in eth_rx domain
+ # and measure ticks period in sys_clk domain.
+
+ # Generate a tick every 1024 clock cycles (eth_rx clock domain)
+ eth_tick = Signal()
+ eth_counter = Signal(10)
+ self.sync.eth_rx += eth_counter.eq(eth_counter + 1)
+ self.comb += eth_tick.eq(eth_counter == 0)
+
+ # Synchronize tick (sys clock domain)
+ sys_tick = Signal()
+ eth_ps = PulseSynchronizer("eth_rx", "sys")
+ self.comb += [
+ eth_ps.i.eq(eth_tick),
+ sys_tick.eq(eth_ps.o)
+ ]
+ self.submodules += eth_ps
+
+ # sys_clk domain counter
+ sys_counter = Counter(24)
+ self.submodules += sys_counter
+
+ fsm = FSM(reset_state="IDLE")
+ self.submodules += fsm
+
+ fsm.act("IDLE",
+ sys_counter.reset.eq(1),
+ If(sys_tick,
+ NextState("COUNT")
+ )
+ )
+ fsm.act("COUNT",
+ sys_counter.ce.eq(1),
+ If(sys_tick,
+ NextState("DETECTION")
+ )
+ )
+ fsm.act("DETECTION",
+ update_mode.eq(1),
+ # if freq < 125MHz-5% use MII mode
+ If(sys_counter.value > int((clk_freq/125000000)*1024*1.05),
+ mode.eq(1)
+ # if freq >= 125MHz-5% use GMII mode
+ ).Else(
+ mode.eq(0)
+ ),
+ NextState("IDLE")
+ )
+
+
+class LiteEthPHYGMIIMII(Module, AutoCSR):
+ def __init__(self, clock_pads, pads, clk_freq, with_hw_init_reset=True):
+ self.dw = 8
+ # Note: we can use GMII CRG since it also handles tx clock pad used for MII
+ self.submodules.mode_detection = LiteEthGMIIMIIModeDetection(clk_freq)
+ mode = self.mode_detection.mode
+ self.submodules.crg = LiteEthPHYGMIICRG(clock_pads, pads, with_hw_init_reset, mode == modes["MII"])
+ self.submodules.tx = RenameClockDomains(LiteEthPHYGMIIMIITX(pads, mode), "eth_tx")
+ self.submodules.rx = RenameClockDomains(LiteEthPHYGMIIMIIRX(pads, mode), "eth_rx")
+ self.sink, self.source = self.tx.sink, self.rx.source
--- /dev/null
+from misoc.com.liteethmini.common import *
+from misoc.com.liteethmini.generic import *
+
+
+class LiteEthPHYLoopbackCRG(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 LiteEthPHYLoopback(Module, AutoCSR):
+ def __init__(self):
+ self.dw = 8
+ self.submodules.crg = LiteEthLoopbackPHYCRG()
+ self.sink = sink = Sink(eth_phy_description(8))
+ self.source = source = Source(eth_phy_description(8))
+ self.comb += Record.connect(self.sink, self.source)
--- /dev/null
+from misoc.com.liteethmini.common import *
+
+
+def converter_description(dw):
+ payload_layout = [("data", dw)]
+ return EndpointDescription(payload_layout, packetized=True)
+
+
+class LiteEthPHYMIITX(Module):
+ def __init__(self, pads, pads_register=True):
+ self.sink = sink = Sink(eth_phy_description(8))
+
+ # # #
+
+ if hasattr(pads, "tx_er"):
+ self.sync += pads.tx_er.eq(0)
+ converter = Converter(converter_description(8),
+ converter_description(4))
+ self.submodules += converter
+ self.comb += [
+ converter.sink.stb.eq(sink.stb),
+ converter.sink.data.eq(sink.data),
+ sink.ack.eq(converter.sink.ack),
+ converter.source.ack.eq(1)
+ ]
+ pads_eq = [
+ pads.tx_en.eq(converter.source.stb),
+ pads.tx_data.eq(converter.source.data)
+ ]
+ if pads_register:
+ self.sync += pads_eq
+ else:
+ self.comb += pads_eq
+
+
+class LiteEthPHYMIIRX(Module):
+ def __init__(self, pads):
+ self.source = source = Source(eth_phy_description(8))
+
+ # # #
+
+ sop = FlipFlop(reset=1)
+ self.submodules += sop
+
+ converter = Converter(converter_description(4),
+ converter_description(8))
+ converter = InsertReset(converter)
+ self.submodules += converter
+
+ self.sync += [
+ converter.reset.eq(~pads.dv),
+ converter.sink.stb.eq(1),
+ converter.sink.data.eq(pads.rx_data)
+ ]
+ self.comb += [
+ sop.reset.eq(~pads.dv),
+ sop.ce.eq(pads.dv),
+ converter.sink.sop.eq(sop.q),
+ converter.sink.eop.eq(~pads.dv)
+ ]
+ self.comb += Record.connect(converter.source, source)
+
+
+class LiteEthPHYMIICRG(Module, AutoCSR):
+ def __init__(self, clock_pads, pads, with_hw_init_reset):
+ self._reset = CSRStorage()
+
+ # # #
+
+ if hasattr(clock_pads, "phy"):
+ 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)
+
+ if with_hw_init_reset:
+ reset = Signal()
+ counter_done = Signal()
+ self.submodules.counter = counter = Counter(max=512)
+ self.comb += [
+ counter_done.eq(counter.value == 256),
+ counter.ce.eq(~counter_done),
+ reset.eq(~counter_done | self._reset.storage)
+ ]
+ else:
+ 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 LiteEthPHYMII(Module, AutoCSR):
+ def __init__(self, clock_pads, pads, with_hw_init_reset=True):
+ self.dw = 8
+ self.submodules.crg = LiteEthPHYMIICRG(clock_pads, pads, with_hw_init_reset)
+ self.submodules.tx = RenameClockDomains(LiteEthPHYMIITX(pads), "eth_tx")
+ self.submodules.rx = RenameClockDomains(LiteEthPHYMIIRX(pads), "eth_rx")
+ self.sink, self.source = self.tx.sink, self.rx.source
--- /dev/null
+# RGMII PHY for Spartan-6
+
+from migen.genlib.io import DDROutput
+from migen.genlib.misc import WaitTimer
+from migen.genlib.fsm import FSM, NextState
+
+from misoc.com.liteethmini.common import *
+
+
+class LiteEthPHYRGMIITX(Module):
+ def __init__(self, pads, pads_register=True):
+ self.sink = sink = Sink(eth_phy_description(8))
+
+ # # #
+
+ self.specials += Instance("ODDR2",
+ p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="ASYNC",
+ i_C0=ClockSignal("eth_tx"), i_C1=~ClockSignal("eth_tx"),
+ i_CE=1, i_S=0, i_R=0,
+ i_D0=sink.stb, i_D1=sink.stb, o_Q=pads.tx_ctl,
+ )
+ for i in range(4):
+ self.specials += Instance("ODDR2",
+ p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="ASYNC",
+ i_C0=ClockSignal("eth_tx"), i_C1=~ClockSignal("eth_tx"),
+ i_CE=1, i_S=0, i_R=0,
+ i_D0=sink.data[i], i_D1=sink.data[4+i], o_Q=pads.tx_data[i],
+ )
+ self.comb += sink.ack.eq(1)
+
+
+class LiteEthPHYRGMIIRX(Module):
+ def __init__(self, pads):
+ self.source = source = Source(eth_phy_description(8))
+
+ # # #
+
+ rx_ctl = Signal()
+ rx_data = Signal(8)
+
+ self.specials += Instance("IDDR2",
+ p_DDR_ALIGNMENT="C0", p_INIT_Q0=0, p_INIT_Q1=0, p_SRTYPE="ASYNC",
+ i_C0=ClockSignal("eth_rx"), i_C1=~ClockSignal("eth_rx"),
+ i_CE=1, i_S=0, i_R=0,
+ i_D=pads.rx_ctl, o_Q1=rx_ctl,
+ )
+ for i in range(4):
+ self.specials += Instance("IDDR2",
+ p_DDR_ALIGNMENT="C0", p_INIT_Q0=0, p_INIT_Q1=0, p_SRTYPE="ASYNC",
+ i_C0=ClockSignal("eth_rx"), i_C1=~ClockSignal("eth_rx"),
+ i_CE=1, i_S=0, i_R=0,
+ i_D=pads.rx_data[i], o_Q0=rx_data[4+i], o_Q1=rx_data[i],
+ )
+
+
+ rx_ctl_d = Signal()
+ self.sync += rx_ctl_d.eq(rx_ctl)
+
+ sop = Signal()
+ eop = Signal()
+ self.comb += [
+ sop.eq(rx_ctl & ~rx_ctl_d),
+ eop.eq(~rx_ctl & rx_ctl_d)
+ ]
+ self.sync += [
+ source.stb.eq(rx_ctl),
+ source.sop.eq(sop),
+ source.data.eq(rx_data)
+ ]
+ self.comb += source.eop.eq(eop)
+
+
+class LiteEthPHYRGMIICRG(Module, AutoCSR):
+ def __init__(self, clock_pads, pads, with_hw_init_reset):
+ self._reset = CSRStorage()
+
+ # # #
+
+ self.clock_domains.cd_eth_rx = ClockDomain()
+ self.clock_domains.cd_eth_tx = ClockDomain()
+
+
+ # RX
+ dcm_reset = Signal()
+ dcm_locked = Signal()
+
+ timer = WaitTimer(1024)
+ fsm = FSM(reset_state="DCM_RESET")
+ self.submodules += timer, fsm
+
+ fsm.act("DCM_RESET",
+ dcm_reset.eq(1),
+ timer.wait.eq(1),
+ If(timer.done,
+ timer.wait.eq(0),
+ NextState("DCM_WAIT")
+ )
+ )
+ fsm.act("DCM_WAIT",
+ timer.wait.eq(1),
+ If(timer.done,
+ NextState("DCM_CHECK_LOCK")
+ )
+ )
+ fsm.act("DCM_CHECK_LOCK",
+ If(~dcm_locked,
+ NextState("DCM_RESET")
+ )
+ )
+
+ clk90_rx = Signal()
+ clk0_rx = Signal()
+ clk0_rx_bufg = Signal()
+ self.specials += Instance("DCM",
+ i_CLKIN=clock_pads.rx,
+ i_CLKFB=clk0_rx_bufg,
+ o_CLK0=clk0_rx,
+ o_CLK90=clk90_rx,
+ o_LOCKED=dcm_locked,
+ i_PSEN=0,
+ i_PSCLK=0,
+ i_PSINCDEC=0,
+ i_RST=dcm_reset
+ )
+
+ self.specials += Instance("BUFG", i_I=clk0_rx, o_O=clk0_rx_bufg)
+ self.specials += Instance("BUFG", i_I=clk90_rx, o_O=self.cd_eth_rx.clk)
+
+ # TX
+ self.specials += DDROutput(1, 0, clock_pads.tx, ClockSignal("eth_tx"))
+ self.specials += Instance("BUFG", i_I=self.cd_eth_rx.clk, o_O=self.cd_eth_tx.clk)
+
+ # Reset
+ if with_hw_init_reset:
+ reset = Signal()
+ counter_done = Signal()
+ self.submodules.counter = counter = Counter(max=512)
+ self.comb += [
+ counter_done.eq(counter.value == 256),
+ counter.ce.eq(~counter_done),
+ reset.eq(~counter_done | self._reset.storage)
+ ]
+ else:
+ 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 LiteEthPHYRGMII(Module, AutoCSR):
+ def __init__(self, clock_pads, pads, with_hw_init_reset=True):
+ self.dw = 8
+ self.submodules.crg = LiteEthPHYRGMIICRG(clock_pads,
+ pads,
+ with_hw_init_reset)
+ self.submodules.tx = RenameClockDomains(LiteEthPHYRGMIITX(pads),
+ "eth_tx")
+ self.submodules.rx = RenameClockDomains(LiteEthPHYRGMIIRX(pads),
+ "eth_rx")
+ self.sink, self.source = self.tx.sink, self.rx.source
--- /dev/null
+import os
+
+from misoc.com.liteethmini.common import *
+
+
+class LiteEthPHYSimCRG(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 LiteEthPHYSim(Module, AutoCSR):
+ def __init__(self, pads, tap="tap0", ip_address="192.168.0.14"):
+ self.dw = 8
+ self.submodules.crg = LiteEthPHYSimCRG()
+ self.sink = sink = Sink(eth_phy_description(8))
+ self.source = source = Source(eth_phy_description(8))
+ self.tap = tap
+ self.ip_address = ip_address
+
+ self.comb += [
+ pads.source_stb.eq(self.sink.stb),
+ pads.source_data.eq(self.sink.data),
+ self.sink.ack.eq(1)
+ ]
+
+ self.sync += [
+ self.source.stb.eq(pads.sink_stb),
+ self.source.sop.eq(pads.sink_stb & ~self.source.stb),
+ self.source.data.eq(pads.sink_data),
+ ]
+ self.comb += [
+ self.source.eop.eq(~pads.sink_stb & self.source.stb),
+ ]
+
+ # XXX avoid use of os.system
+ os.system("openvpn --mktun --dev {}".format(self.tap))
+ os.system("ifconfig {} {} up".format(self.tap, self.ip_address))
+ os.system("mknod /dev/net/{} c 10 200".format(self.tap))
+
+ def do_exit(self, *args, **kwargs):
+ # XXX avoid use of os.system
+ os.system("rm -f /dev/net/{}".format(self.tap))
+ os.system("openvpn --rmtun --dev {}".format(self.tap))
--- /dev/null
+import os
+
+from migen import *
+from migen.bus import wishbone
+
+
+class LM32(Module):
+ def __init__(self, platform, eba_reset):
+ self.ibus = i = wishbone.Interface()
+ self.dbus = d = wishbone.Interface()
+ self.interrupt = Signal(32)
+
+ ###
+
+ i_adr_o = Signal(32)
+ d_adr_o = Signal(32)
+ self.specials += Instance("lm32_cpu",
+ p_eba_reset=Instance.PreformattedParam("32'h{:08x}".format(eba_reset)),
+
+ i_clk_i=ClockSignal(),
+ i_rst_i=ResetSignal(),
+
+ i_interrupt=self.interrupt,
+
+ o_I_ADR_O=i_adr_o,
+ o_I_DAT_O=i.dat_w,
+ o_I_SEL_O=i.sel,
+ o_I_CYC_O=i.cyc,
+ o_I_STB_O=i.stb,
+ o_I_WE_O=i.we,
+ o_I_CTI_O=i.cti,
+ o_I_BTE_O=i.bte,
+ i_I_DAT_I=i.dat_r,
+ i_I_ACK_I=i.ack,
+ i_I_ERR_I=i.err,
+ i_I_RTY_I=0,
+
+ o_D_ADR_O=d_adr_o,
+ o_D_DAT_O=d.dat_w,
+ o_D_SEL_O=d.sel,
+ o_D_CYC_O=d.cyc,
+ o_D_STB_O=d.stb,
+ o_D_WE_O=d.we,
+ o_D_CTI_O=d.cti,
+ o_D_BTE_O=d.bte,
+ i_D_DAT_I=d.dat_r,
+ i_D_ACK_I=d.ack,
+ i_D_ERR_I=d.err,
+ i_D_RTY_I=0)
+
+ self.comb += [
+ self.ibus.adr.eq(i_adr_o[2:]),
+ self.dbus.adr.eq(d_adr_o[2:])
+ ]
+
+ # add Verilog sources
+ platform.add_sources(os.path.join("extcores", "lm32", "submodule", "rtl"),
+ "lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v",
+ "lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v",
+ "lm32_shifter.v", "lm32_multiplier.v", "lm32_mc_arithmetic.v",
+ "lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v",
+ "lm32_dcache.v", "lm32_debug.v", "lm32_itlb.v", "lm32_dtlb.v")
+ platform.add_verilog_include_path(os.path.join("extcores", "lm32"))
--- /dev/null
+`ifdef LM32_CONFIG_V
+`else
+`define LM32_CONFIG_V
+
+//
+// EXCEPTION VECTORS BASE ADDRESS
+//
+
+// Base address for exception vectors
+`define CFG_EBA_RESET 32'h00000000
+
+// Base address for the debug exception vectors. If the DC_RE flag is
+// set or the at_debug signal is asserted (see CFG_ALTERNATE_EBA) this
+// will also be used for normal exception vectors.
+`define CFG_DEBA_RESET 32'h10000000
+
+// Enable exception vector remapping by external signal
+//`define CFG_ALTERNATE_EBA
+
+
+//
+// ALU OPTIONS
+//
+
+// Enable sign-extension instructions
+`define CFG_SIGN_EXTEND_ENABLED
+
+// Shifter
+// You may either enable the piplined or the multi-cycle barrel
+// shifter. The multi-cycle shifter will stall the pipeline until
+// the result is available after 32 cycles.
+// If both options are disabled, only "right shift by one bit" is
+// available.
+//`define CFG_MC_BARREL_SHIFT_ENABLED
+`define CFG_PL_BARREL_SHIFT_ENABLED
+
+// Multiplier
+// The multiplier is available either in a multi-cycle version or
+// in a pipelined one. The multi-cycle multiplier stalls the pipe
+// for 32 cycles. If both options are disabled, multiply operations
+// are not supported.
+//`define CFG_MC_MULTIPLY_ENABLED
+`define CFG_PL_MULTIPLY_ENABLED
+
+// Enable the multi-cycle divider. Stalls the pipe until the result
+// is ready after 32 cycles. If disabled, the divide operation is not
+// supported.
+`define CFG_MC_DIVIDE_ENABLED
+
+
+//
+// INTERRUPTS
+//
+
+// Enable support for 32 hardware interrupts
+`define CFG_INTERRUPTS_ENABLED
+
+// Enable level-sensitive interrupts. The interrupt line status is
+// reflected in the IP register, which is then read-only.
+`define CFG_LEVEL_SENSITIVE_INTERRUPTS
+
+
+//
+// USER INSTRUCTION
+//
+
+// Enable support for the user opcode.
+//`define CFG_USER_ENABLED
+
+
+//
+// MEMORY MANAGEMENT UNIT
+//
+
+// Enable instruction and data translation lookaside buffers and
+// restricted user mode.
+//`define CFG_MMU_ENABLED
+
+
+//
+// CACHE
+//
+
+// Instruction cache
+`define CFG_ICACHE_ENABLED
+`define CFG_ICACHE_ASSOCIATIVITY 1
+`define CFG_ICACHE_SETS 256
+`define CFG_ICACHE_BYTES_PER_LINE 16
+`define CFG_ICACHE_BASE_ADDRESS 32'h00000000
+`define CFG_ICACHE_LIMIT 32'h7fffffff
+
+// Data cache
+`define CFG_DCACHE_ENABLED
+`define CFG_DCACHE_ASSOCIATIVITY 1
+`define CFG_DCACHE_SETS 256
+`define CFG_DCACHE_BYTES_PER_LINE 16
+`define CFG_DCACHE_BASE_ADDRESS 32'h00000000
+`define CFG_DCACHE_LIMIT 32'h7fffffff
+
+
+//
+// DEBUG OPTION
+//
+
+// Globally enable debugging
+//`define CFG_DEBUG_ENABLED
+
+// Enable the hardware JTAG debugging interface.
+// Note: to use this, there must be a special JTAG module for your
+// device. At the moment, there is only support for the
+// Spartan-6.
+//`define CFG_JTAG_ENABLED
+
+// JTAG UART is a communication channel which uses JTAG to transmit
+// and receive bytes to and from the host computer.
+//`define CFG_JTAG_UART_ENABLED
+
+// Enable reading and writing to the memory and writing CSRs using
+// the JTAG interface.
+//`define CFG_HW_DEBUG_ENABLED
+
+// Number of hardware watchpoints, max. 4
+//`define CFG_WATCHPOINTS 32'h4
+
+// Enable hardware breakpoints
+//`define CFG_ROM_DEBUG_ENABLED
+
+// Number of hardware breakpoints, max. 4
+//`define CFG_BREAKPOINTS 32'h4
+
+// Put the processor into debug mode by an external signal. That is,
+// raise a breakpoint exception. This is useful if you have a debug
+// monitor and a serial line and you want to trap into the monitor on a
+// BREAK symbol on the serial line.
+//`define CFG_EXTERNAL_BREAK_ENABLED
+
+
+//
+// REGISTER FILE
+//
+
+// The following option explicitly infers block RAM for the register
+// file. There is extra logic to avoid parallel writes and reads.
+// Normally, if your synthesizer is smart enough, this should not be
+// necessary because it will automatically infer block RAM for you.
+//`define CFG_EBR_POSEDGE_REGISTER_FILE
+
+// Explicitly infers block RAM, too. But it uses two different clocks,
+// one being shifted by 180deg, for the read and write port. Therefore,
+// no additional logic to avoid the parallel write/reads.
+//`define CFG_EBR_NEGEDGE_REGISTER_FILE
+
+
+//
+// MISCELLANEOUS
+//
+
+// Exceptions on wishbone bus errors
+//`define CFG_BUS_ERRORS_ENABLED
+
+// Enable the cycle counter
+`define CFG_CYCLE_COUNTER_ENABLED
+
+// Embedded instruction ROM using on-chip block RAM
+//`define CFG_IROM_ENABLED
+//`define CFG_IROM_INIT_FILE "NONE"
+//`define CFG_IROM_BASE_ADDRESS 32'h10000000
+//`define CFG_IROM_LIMIT 32'h10000fff
+
+// Embedded data RAM using on-chip block RAM
+//`define CFG_DRAM_ENABLED
+//`define CFG_DRAM_INIT_FILE "NONE"
+//`define CFG_DRAM_BASE_ADDRESS 32'h20000000
+//`define CFG_DRAM_LIMIT 32'h20000fff
+
+// Trace unit
+//`define CFG_TRACE_ENABLED
+
+// Resolve unconditional branches already in the X stage (UNTESTED!)
+//`define CFG_FAST_UNCONDITIONAL_BRANCH
+
+// log2 function
+// If your simulator/synthesizer does not support the $clog2 system
+// function you can use a constant function instead.
+
+function integer clog2;
+ input integer value;
+ begin
+ value = value - 1;
+ for (clog2 = 0; value > 0; clog2 = clog2 + 1)
+ value = value >> 1;
+ end
+endfunction
+
+`define CLOG2 clog2
+
+//`define CLOG2 $clog2
+
+`endif
+++ /dev/null
-from migen import *
-from migen.bus import wishbone
-from migen.genlib.fsm import FSM, NextState
-
-
-class NorFlash16(Module):
- def __init__(self, pads, rd_timing, wr_timing):
- self.bus = wishbone.Interface()
-
- ###
-
- data = TSTriple(16)
- lsb = Signal()
-
- self.specials += data.get_tristate(pads.d)
- self.comb += [
- data.oe.eq(pads.oe_n),
- pads.ce_n.eq(0)
- ]
-
- load_lo = Signal()
- load_hi = Signal()
- store = Signal()
-
- pads.oe_n.reset, pads.we_n.reset = 1, 1
- self.sync += [
- pads.oe_n.eq(1),
- pads.we_n.eq(1),
-
- # Register data/address to avoid off-chip glitches
- If(self.bus.cyc & self.bus.stb,
- pads.adr.eq(Cat(lsb, self.bus.adr)),
- If(self.bus.we,
- # Only 16-bit writes are supported. Assume sel=0011 or 1100.
- If(self.bus.sel[0],
- data.o.eq(self.bus.dat_w[:16])
- ).Else(
- data.o.eq(self.bus.dat_w[16:])
- )
- ).Else(
- pads.oe_n.eq(0)
- )
- ),
-
- If(load_lo, self.bus.dat_r[:16].eq(data.i)),
- If(load_hi, self.bus.dat_r[16:].eq(data.i)),
- If(store, pads.we_n.eq(0))
- ]
-
- # Typical timing of the flash chips:
- # - 110ns address to output
- # - 50ns write pulse width
- counter = Signal(max=max(rd_timing, wr_timing)+1)
- counter_en = Signal()
- counter_wr_mode = Signal()
- counter_done = Signal()
- self.comb += counter_done.eq(counter == Mux(counter_wr_mode, wr_timing, rd_timing))
- self.sync += If(counter_en & ~counter_done,
- counter.eq(counter + 1)
- ).Else(
- counter.eq(0)
- )
-
- fsm = FSM()
- self.submodules += fsm
-
- fsm.act("IDLE",
- If(self.bus.cyc & self.bus.stb,
- If(self.bus.we,
- NextState("WR")
- ).Else(
- NextState("RD_HI")
- )
- )
- )
- fsm.act("RD_HI",
- lsb.eq(0),
- counter_en.eq(1),
- If(counter_done,
- load_hi.eq(1),
- NextState("RD_LO")
- )
- )
- fsm.act("RD_LO",
- lsb.eq(1),
- counter_en.eq(1),
- If(counter_done,
- load_lo.eq(1),
- NextState("ACK")
- )
- )
- fsm.act("WR",
- # supported cases: sel=0011 [lsb=1] and sel=1100 [lsb=0]
- lsb.eq(self.bus.sel[0]),
- counter_wr_mode.eq(1),
- counter_en.eq(1),
- store.eq(1),
- If(counter_done, NextState("ACK"))
- )
- fsm.act("ACK",
- self.bus.ack.eq(1),
- NextState("IDLE")
- )
+++ /dev/null
-from migen import *
-from migen.bus.transactions import *
-from migen.bus import wishbone
-from migen.genlib.misc import timeline
-from migen.genlib.record import Record
-from migen.bank.description import AutoCSR, CSRStorage, CSRStatus
-
-_FAST_READ = 0x0b
-_DIOFR = 0xbb
-_QIOFR = 0xeb
-
-
-def _format_cmd(cmd, spi_width):
- """
- `cmd` is the read instruction. Since everything is transmitted on all
- dq lines (cmd, adr and data), extend/interleave cmd to full pads.dq
- width even if dq1-dq3 are don't care during the command phase:
- For example, for N25Q128, 0xeb is the quad i/o fast read, and
- extended to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff
- """
- c = 2**(8*spi_width)-1
- for b in range(8):
- if not (cmd>>b)%2:
- c &= ~(1<<(b*spi_width))
- return c
-
-
-class SpiFlash(Module, AutoCSR):
- def __init__(self, pads, dummy=15, div=2, with_bitbang=True):
- """
- Simple SPI flash, e.g. N25Q128 on the LX9 Microboard.
-
- Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
- Read). Only supports mode0 (cpol=0, cpha=0).
- Optionally supports software bitbanging (for write, erase, or other commands).
- """
- self.bus = bus = wishbone.Interface()
- spi_width = flen(pads.dq)
- if with_bitbang:
- self.bitbang = CSRStorage(4)
- self.miso = CSRStatus()
- self.bitbang_en = CSRStorage()
-
- ###
-
- cs_n = Signal(reset=1)
- clk = Signal()
- dq_oe = Signal()
- wbone_width = flen(bus.dat_r)
-
-
- read_cmd_params = {
- 4: (_format_cmd(_QIOFR, 4), 4*8),
- 2: (_format_cmd(_DIOFR, 2), 2*8),
- 1: (_format_cmd(_FAST_READ, 1), 1*8)
- }
- read_cmd, cmd_width = read_cmd_params[spi_width]
- addr_width = 24
-
- pads.cs_n.reset = 1
-
- dq = TSTriple(spi_width)
- self.specials.dq = dq.get_tristate(pads.dq)
-
- sr = Signal(max(cmd_width, addr_width, wbone_width))
- dqs = Replicate(1, spi_width-1)
-
- self.comb += bus.dat_r.eq(sr)
-
- hw_read_logic = [
- pads.clk.eq(clk),
- pads.cs_n.eq(cs_n),
- dq.o.eq(sr[-spi_width:]),
- dq.oe.eq(dq_oe)
- ]
-
- if with_bitbang:
- bitbang_logic = [
- pads.clk.eq(self.bitbang.storage[1]),
- pads.cs_n.eq(self.bitbang.storage[2]),
- dq.o.eq(Cat(self.bitbang.storage[0], dqs)),
- If(self.bitbang.storage[3],
- dq.oe.eq(0)
- ).Else(
- dq.oe.eq(1)
- ),
- If(self.bitbang.storage[1],
- self.miso.status.eq(dq.i[1])
- )
- ]
-
- self.comb += \
- If(self.bitbang_en.storage,
- bitbang_logic
- ).Else(
- hw_read_logic
- )
- else:
- self.comb += hw_read_logic
-
- if div < 2:
- raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
- else:
- i = Signal(max=div)
- dqi = Signal(spi_width)
- self.sync += [
- If(i == div//2 - 1,
- clk.eq(1),
- dqi.eq(dq.i),
- ),
- If(i == div - 1,
- i.eq(0),
- clk.eq(0),
- sr.eq(Cat(dqi, sr[:-spi_width]))
- ).Else(
- i.eq(i + 1),
- ),
- ]
-
- # spi is byte-addressed, prefix by zeros
- z = Replicate(0, log2_int(wbone_width//8))
-
- seq = [
- (cmd_width//spi_width*div,
- [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]),
- (addr_width//spi_width*div,
- [sr[-addr_width:].eq(Cat(z, bus.adr))]),
- ((dummy + wbone_width//spi_width)*div,
- [dq_oe.eq(0)]),
- (1,
- [bus.ack.eq(1), cs_n.eq(1)]),
- (div, # tSHSL!
- [bus.ack.eq(0)]),
- (0,
- []),
- ]
-
- # accumulate timeline deltas
- t, tseq = 0, []
- for dt, a in seq:
- tseq.append((t, a))
- t += dt
-
- self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
-
-
-class SpiFlashTB(Module):
- def __init__(self):
- self.submodules.master = wishbone.Initiator(self.gen_reads())
- self.pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)])
- self.submodules.slave = SpiFlash(self.pads)
- self.submodules.tap = wishbone.Tap(self.slave.bus)
- self.submodules.intercon = wishbone.InterconnectPointToPoint(
- self.master.bus, self.slave.bus)
- self.cycle = 0
-
- def gen_reads(self):
- for a in range(10):
- t = TRead(a)
- yield t
- print("read {} in {} cycles(s)".format(t.data, t.latency))
-
- def do_simulation(self, selfp):
- if selfp.pads.cs_n:
- self.cycle = 0
- else:
- self.cycle += 1
- if not selfp.slave.dq.oe:
- selfp.slave.dq.i = self.cycle & 0xf
- do_simulation.passive = True
-
-if __name__ == "__main__":
- from migen.sim.generic import run_simulation
- from migen.fhdl import verilog
-
- pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)])
- s = SpiFlash(pads)
- print(verilog.convert(s, ios={pads.clk, pads.cs_n, pads.dq, s.bus.adr,
- s.bus.dat_r, s.bus.cyc, s.bus.ack, s.bus.stb}))
-
- run_simulation(SpiFlashTB(), vcd_name="spiflash.vcd")
--- /dev/null
+import os
+
+from migen import *
+from migen.bus import wishbone
+
+
+class MOR1KX(Module):
+ def __init__(self, platform, reset_pc):
+ self.ibus = i = wishbone.Interface()
+ self.dbus = d = wishbone.Interface()
+ self.interrupt = Signal(32)
+
+ ###
+
+ i_adr_o = Signal(32)
+ d_adr_o = Signal(32)
+ self.specials += Instance("mor1kx",
+ p_FEATURE_INSTRUCTIONCACHE="ENABLED",
+ p_OPTION_ICACHE_BLOCK_WIDTH=4,
+ p_OPTION_ICACHE_SET_WIDTH=8,
+ p_OPTION_ICACHE_WAYS=1,
+ p_OPTION_ICACHE_LIMIT_WIDTH=31,
+ p_FEATURE_DATACACHE="ENABLED",
+ p_OPTION_DCACHE_BLOCK_WIDTH=4,
+ p_OPTION_DCACHE_SET_WIDTH=8,
+ p_OPTION_DCACHE_WAYS=1,
+ p_OPTION_DCACHE_LIMIT_WIDTH=31,
+ p_FEATURE_TIMER="NONE",
+ p_OPTION_PIC_TRIGGER="LEVEL",
+ p_FEATURE_SYSCALL="NONE",
+ p_FEATURE_TRAP="NONE",
+ p_FEATURE_RANGE="NONE",
+ p_FEATURE_OVERFLOW="NONE",
+ p_FEATURE_ADDC="ENABLED",
+ p_FEATURE_CMOV="ENABLED",
+ p_FEATURE_FFL1="ENABLED",
+ p_OPTION_CPU0="CAPPUCCINO",
+ p_OPTION_RESET_PC=reset_pc,
+ p_IBUS_WB_TYPE="B3_REGISTERED_FEEDBACK",
+ p_DBUS_WB_TYPE="B3_REGISTERED_FEEDBACK",
+
+ i_clk=ClockSignal(),
+ i_rst=ResetSignal(),
+
+ i_irq_i=self.interrupt,
+
+ o_iwbm_adr_o=i_adr_o,
+ o_iwbm_dat_o=i.dat_w,
+ o_iwbm_sel_o=i.sel,
+ o_iwbm_cyc_o=i.cyc,
+ o_iwbm_stb_o=i.stb,
+ o_iwbm_we_o=i.we,
+ o_iwbm_cti_o=i.cti,
+ o_iwbm_bte_o=i.bte,
+ i_iwbm_dat_i=i.dat_r,
+ i_iwbm_ack_i=i.ack,
+ i_iwbm_err_i=i.err,
+ i_iwbm_rty_i=0,
+
+ o_dwbm_adr_o=d_adr_o,
+ o_dwbm_dat_o=d.dat_w,
+ o_dwbm_sel_o=d.sel,
+ o_dwbm_cyc_o=d.cyc,
+ o_dwbm_stb_o=d.stb,
+ o_dwbm_we_o=d.we,
+ o_dwbm_cti_o=d.cti,
+ o_dwbm_bte_o=d.bte,
+ i_dwbm_dat_i=d.dat_r,
+ i_dwbm_ack_i=d.ack,
+ i_dwbm_err_i=d.err,
+ i_dwbm_rty_i=0)
+
+ self.comb += [
+ self.ibus.adr.eq(i_adr_o[2:]),
+ self.dbus.adr.eq(d_adr_o[2:])
+ ]
+
+ # add Verilog sources
+ platform.add_source_dir(os.path.join("extcores", "mor1kx", "submodule",
+ "rtl", "verilog"))
--- /dev/null
+from migen import *
+from migen.bus import wishbone
+from migen.genlib.fsm import FSM, NextState
+
+
+class NorFlash16(Module):
+ def __init__(self, pads, rd_timing, wr_timing):
+ self.bus = wishbone.Interface()
+
+ ###
+
+ data = TSTriple(16)
+ lsb = Signal()
+
+ self.specials += data.get_tristate(pads.d)
+ self.comb += [
+ data.oe.eq(pads.oe_n),
+ pads.ce_n.eq(0)
+ ]
+
+ load_lo = Signal()
+ load_hi = Signal()
+ store = Signal()
+
+ pads.oe_n.reset, pads.we_n.reset = 1, 1
+ self.sync += [
+ pads.oe_n.eq(1),
+ pads.we_n.eq(1),
+
+ # Register data/address to avoid off-chip glitches
+ If(self.bus.cyc & self.bus.stb,
+ pads.adr.eq(Cat(lsb, self.bus.adr)),
+ If(self.bus.we,
+ # Only 16-bit writes are supported. Assume sel=0011 or 1100.
+ If(self.bus.sel[0],
+ data.o.eq(self.bus.dat_w[:16])
+ ).Else(
+ data.o.eq(self.bus.dat_w[16:])
+ )
+ ).Else(
+ pads.oe_n.eq(0)
+ )
+ ),
+
+ If(load_lo, self.bus.dat_r[:16].eq(data.i)),
+ If(load_hi, self.bus.dat_r[16:].eq(data.i)),
+ If(store, pads.we_n.eq(0))
+ ]
+
+ # Typical timing of the flash chips:
+ # - 110ns address to output
+ # - 50ns write pulse width
+ counter = Signal(max=max(rd_timing, wr_timing)+1)
+ counter_en = Signal()
+ counter_wr_mode = Signal()
+ counter_done = Signal()
+ self.comb += counter_done.eq(counter == Mux(counter_wr_mode, wr_timing, rd_timing))
+ self.sync += If(counter_en & ~counter_done,
+ counter.eq(counter + 1)
+ ).Else(
+ counter.eq(0)
+ )
+
+ fsm = FSM()
+ self.submodules += fsm
+
+ fsm.act("IDLE",
+ If(self.bus.cyc & self.bus.stb,
+ If(self.bus.we,
+ NextState("WR")
+ ).Else(
+ NextState("RD_HI")
+ )
+ )
+ )
+ fsm.act("RD_HI",
+ lsb.eq(0),
+ counter_en.eq(1),
+ If(counter_done,
+ load_hi.eq(1),
+ NextState("RD_LO")
+ )
+ )
+ fsm.act("RD_LO",
+ lsb.eq(1),
+ counter_en.eq(1),
+ If(counter_done,
+ load_lo.eq(1),
+ NextState("ACK")
+ )
+ )
+ fsm.act("WR",
+ # supported cases: sel=0011 [lsb=1] and sel=1100 [lsb=0]
+ lsb.eq(self.bus.sel[0]),
+ counter_wr_mode.eq(1),
+ counter_en.eq(1),
+ store.eq(1),
+ If(counter_done, NextState("ACK"))
+ )
+ fsm.act("ACK",
+ self.bus.ack.eq(1),
+ NextState("IDLE")
+ )
+++ /dev/null
-from operator import itemgetter
-
-from migen import *
-from migen.bank import csrgen
-from migen.bus import wishbone, csr, wishbone2csr
-
-from misoc.com.uart.phy import UARTPHY
-from misoc.com import uart
-from misoc.cpu import lm32, mor1kx
-from misoc.cpu import identifier, timer
-
-
-def mem_decoder(address, start=26, end=29):
- return lambda a: a[start:end] == ((address >> (start+2)) & (2**(end-start))-1)
-
-
-class SoC(Module):
- csr_map = {
- "crg": 0, # user
- "uart_phy": 1, # provided by default (optional)
- "uart": 2, # provided by default (optional)
- "identifier": 3, # provided by default (optional)
- "timer0": 4, # provided by default (optional)
- "buttons": 5, # user
- "leds": 6, # user
- }
- interrupt_map = {
- "uart": 0,
- "timer0": 1,
- }
- mem_map = {
- "rom": 0x00000000, # (default shadow @0x80000000)
- "sram": 0x10000000, # (default shadow @0x90000000)
- "main_ram": 0x40000000, # (default shadow @0xc0000000)
- "csr": 0x60000000, # (default shadow @0xe0000000)
- }
- def __init__(self, platform, clk_freq,
- cpu_type="lm32", cpu_reset_address=0x00000000,
- integrated_rom_size=0,
- integrated_sram_size=4096,
- integrated_main_ram_size=0,
- shadow_base=0x80000000,
- with_csr=True, csr_data_width=8, csr_address_width=14,
- with_uart=True, uart_baudrate=115200,
- with_identifier=True,
- with_timer=True):
- self.platform = platform
- self.clk_freq = clk_freq
-
- self.cpu_type = cpu_type
- if integrated_rom_size:
- cpu_reset_address = 0
- self.cpu_reset_address = cpu_reset_address
-
- self.integrated_rom_size = integrated_rom_size
- self.integrated_sram_size = integrated_sram_size
- self.integrated_main_ram_size = integrated_main_ram_size
-
- self.with_uart = with_uart
- self.uart_baudrate = uart_baudrate
-
- self.with_identifier = with_identifier
-
- self.shadow_base = shadow_base
-
- self.with_csr = with_csr
- self.csr_data_width = csr_data_width
- self.csr_address_width = csr_address_width
-
- self._memory_regions = [] # list of (name, origin, length)
- self._csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
- self._constants = [] # list of (name, value)
-
- self._wb_masters = []
- self._wb_slaves = []
-
- if cpu_type != "none":
- if cpu_type == "lm32":
- self.add_cpu_or_bridge(lm32.LM32(platform, self.cpu_reset_address))
- elif cpu_type == "or1k":
- self.add_cpu_or_bridge(mor1kx.MOR1KX(platform, self.cpu_reset_address))
- else:
- raise ValueError("Unsupported CPU type: {}".format(cpu_type))
- self.add_wb_master(self.cpu_or_bridge.ibus)
- self.add_wb_master(self.cpu_or_bridge.dbus)
-
- if integrated_rom_size:
- self.submodules.rom = wishbone.SRAM(integrated_rom_size, read_only=True)
- self.register_rom(self.rom.bus, integrated_rom_size)
-
- if integrated_sram_size:
- self.submodules.sram = wishbone.SRAM(integrated_sram_size)
- self.register_mem("sram", self.mem_map["sram"], self.sram.bus, integrated_sram_size)
-
- # Note: Main Ram can be used when no external SDRAM is available and use SDRAM mapping.
- if integrated_main_ram_size:
- self.submodules.main_ram = wishbone.SRAM(integrated_main_ram_size)
- self.register_mem("main_ram", self.mem_map["main_ram"], self.main_ram.bus, integrated_main_ram_size)
-
- if with_csr:
- self.submodules.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(csr_data_width, csr_address_width))
- self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone)
-
- if with_uart:
- self.submodules.uart_phy = UARTPHY(platform.request("serial"), clk_freq, uart_baudrate)
- self.submodules.uart = uart.UART(self.uart_phy)
-
- if with_identifier:
- platform_id = 0x554E if not hasattr(platform, "identifier") else platform.identifier
- self.submodules.identifier = identifier.Identifier(platform_id, int(clk_freq))
-
- if with_timer:
- self.submodules.timer0 = timer.Timer()
-
- def add_cpu_or_bridge(self, cpu_or_bridge):
- if self.finalized:
- raise FinalizeError
- if hasattr(self, "cpu_or_bridge"):
- raise NotImplementedError("More than one CPU is not supported")
- self.submodules.cpu_or_bridge = cpu_or_bridge
-
- def init_rom(self, data):
- self.rom.mem.init = data
-
- def add_wb_master(self, wbm):
- if self.finalized:
- raise FinalizeError
- self._wb_masters.append(wbm)
-
- def add_wb_slave(self, address_decoder, interface):
- if self.finalized:
- raise FinalizeError
- self._wb_slaves.append((address_decoder, interface))
-
- def add_memory_region(self, name, origin, length):
- def in_this_region(addr):
- return addr >= origin and addr < origin + length
- for n, o, l in self._memory_regions:
- if n == name or in_this_region(o) or in_this_region(o+l-1):
- raise ValueError("Memory region conflict between {} and {}".format(n, name))
-
- self._memory_regions.append((name, origin, length))
-
- def register_mem(self, name, address, interface, size=None):
- self.add_wb_slave(mem_decoder(address), interface)
- if size is not None:
- self.add_memory_region(name, address, size)
-
- def register_rom(self, interface, rom_size=0xa000):
- self.add_wb_slave(mem_decoder(self.mem_map["rom"]), interface)
- self.add_memory_region("rom", self.cpu_reset_address, rom_size)
-
- def get_memory_regions(self):
- return self._memory_regions
-
- def check_csr_region(self, name, origin):
- for n, o, l, obj in self._csr_regions:
- if n == name or o == origin:
- raise ValueError("CSR region conflict between {} and {}".format(n, name))
-
- def add_csr_region(self, name, origin, busword, obj):
- self.check_csr_region(name, origin)
- self._csr_regions.append((name, origin, busword, obj))
-
- def get_csr_regions(self):
- return self._csr_regions
-
- def add_constant(self, name, value=None):
- self._constants.append((name, value))
-
- def get_constants(self):
- r = []
- for name, interrupt in sorted(self.interrupt_map.items(), key=itemgetter(1)):
- r.append((name.upper() + "_INTERRUPT", interrupt))
- r += self._constants
- return r
-
- def do_finalize(self):
- registered_mems = {regions[0] for regions in self._memory_regions}
- if self.cpu_type != "none":
- for mem in "rom", "sram":
- if mem not in registered_mems:
- raise FinalizeError("CPU needs a {} to be registered with SoC.register_mem()".format(mem))
-
- # Wishbone
- self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
- self._wb_slaves, register=True)
-
- # CSR
- if self.with_csr:
- self.submodules.csrbankarray = csrgen.BankArray(self,
- lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
- data_width=self.csr_data_width, address_width=self.csr_address_width)
- self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses())
- for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
- self.add_csr_region(name, (self.mem_map["csr"] + 0x800*mapaddr) | self.shadow_base, self.csr_data_width, csrs)
- for name, memory, mapaddr, mmap in self.csrbankarray.srams:
- self.add_csr_region(name + "_" + memory.name_override, (self.mem_map["csr"] + 0x800*mapaddr) | self.shadow_base, self.csr_data_width, memory)
-
- # Interrupts
- if hasattr(self.cpu_or_bridge, "interrupt"):
- for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)):
- if hasattr(self, k):
- self.comb += self.cpu_or_bridge.interrupt[v].eq(getattr(self, k).ev.irq)
+++ /dev/null
-from migen import *
-from migen.bank.description import CSRStatus
-
-
-def get_cpu_mak(cpu_type):
- if cpu_type == "lm32":
- triple = "lm32-elf"
- cpuflags = "-mbarrel-shift-enabled -mmultiply-enabled -mdivide-enabled -msign-extend-enabled"
- clang = ""
- elif cpu_type == "or1k":
- triple = "or1k-linux"
- cpuflags = "-mhard-mul -mhard-div -mror -mffl1 -maddc"
- clang = "1"
- else:
- raise ValueError("Unsupported CPU type: "+cpu_type)
- return "TRIPLE={}\nCPU={}\nCPUFLAGS={}\nCLANG={}".format(triple, cpu_type, cpuflags, clang)
-
-
-def get_linker_output_format(cpu_type):
- return "OUTPUT_FORMAT(\"elf32-{}\")\n".format(cpu_type)
-
-
-def get_linker_regions(regions):
- r = "MEMORY {\n"
- for name, origin, length in regions:
- r += "\t{} : ORIGIN = 0x{:08x}, LENGTH = 0x{:08x}\n".format(name, origin, length)
- r += "}\n"
- return r
-
-
-def get_mem_header(regions, flash_boot_address):
- r = "#ifndef __GENERATED_MEM_H\n#define __GENERATED_MEM_H\n\n"
- for name, base, size in regions:
- r += "#define {name}_BASE 0x{base:08x}\n#define {name}_SIZE 0x{size:08x}\n\n".format(name=name.upper(), base=base, size=size)
- if flash_boot_address is not None:
- r += "#define FLASH_BOOT_ADDRESS 0x{:08x}\n\n".format(flash_boot_address)
- r += "#endif\n"
- return r
-
-
-def _get_rw_functions(reg_name, reg_base, nwords, busword, read_only, with_access_functions):
- r = ""
-
- r += "#define CSR_"+reg_name.upper()+"_ADDR "+hex(reg_base)+"\n"
- r += "#define CSR_"+reg_name.upper()+"_SIZE "+str(nwords)+"\n"
-
- size = nwords*busword
- if size > 64:
- return r
- elif size > 32:
- ctype = "unsigned long long int"
- elif size > 16:
- ctype = "unsigned int"
- elif size > 8:
- ctype = "unsigned short int"
- else:
- ctype = "unsigned char"
-
- if with_access_functions:
- r += "static inline "+ctype+" "+reg_name+"_read(void) {\n"
- if size > 1:
- r += "\t"+ctype+" r = MMPTR("+hex(reg_base)+");\n"
- for byte in range(1, nwords):
- r += "\tr <<= "+str(busword)+";\n\tr |= MMPTR("+hex(reg_base+4*byte)+");\n"
- r += "\treturn r;\n}\n"
- else:
- r += "\treturn MMPTR("+hex(reg_base)+");\n}\n"
-
- if not read_only:
- r += "static inline void "+reg_name+"_write("+ctype+" value) {\n"
- for word in range(nwords):
- shift = (nwords-word-1)*busword
- if shift:
- value_shifted = "value >> "+str(shift)
- else:
- value_shifted = "value"
- r += "\tMMPTR("+hex(reg_base+4*word)+") = "+value_shifted+";\n"
- r += "}\n"
- return r
-
-
-def get_csr_header(regions, constants, with_access_functions=True):
- r = "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n"
- if with_access_functions:
- r += "#include <hw/common.h>\n"
- for name, origin, busword, obj in regions:
- if isinstance(obj, Memory):
- r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n"
- else:
- r += "\n/* "+name+" */\n"
- r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n"
- for csr in obj:
- nr = (csr.size + busword - 1)//busword
- r += _get_rw_functions(name + "_" + csr.name, origin, nr, busword, isinstance(csr, CSRStatus), with_access_functions)
- origin += 4*nr
-
- r += "\n/* constants */\n"
- for name, value in constants:
- r += "#define " + name
- if value is not None:
- if isinstance(value, str):
- r += " \"" + value + "\""
- else:
- r += " " + str(value)
- r += "\n"
-
- r += "\n#endif\n"
- return r
-
-
-def get_csr_csv(regions):
- r = ""
- for name, origin, busword, obj in regions:
- if not isinstance(obj, Memory):
- for csr in obj:
- nr = (csr.size + busword - 1)//busword
- r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, origin, nr, "ro" if isinstance(csr, CSRStatus) else "rw")
- origin += 4*nr
- return r
+++ /dev/null
-from migen import *
-from migen.bus import wishbone
-from migen.genlib.record import *
-
-from misoc.mem.sdram.core import SDRAMCore
-from misoc.mem.sdram.core.lasmicon import LASMIconSettings
-from misoc.mem.sdram.core.minicon import MiniconSettings
-from misoc.mem.sdram.frontend import memtest, wishbone2lasmi
-from misoc.soc import SoC
-
-
-class SDRAMSoC(SoC):
- csr_map = {
- "sdram": 8,
- "l2_cache": 9,
- "memtest_w": 10,
- "memtest_r": 11
- }
- csr_map.update(SoC.csr_map)
-
- def __init__(self, platform, clk_freq, sdram_controller_settings,
- **kwargs):
- SoC.__init__(self, platform, clk_freq, **kwargs)
- if isinstance(sdram_controller_settings, str):
- self.sdram_controller_settings = eval(sdram_controller_settings)
- else:
- self.sdram_controller_settings = sdram_controller_settings
- self._sdram_phy_registered = False
- self._wb_sdram_ifs = []
- self._wb_sdram = wishbone.Interface()
-
- def add_wb_sdram_if(self, interface):
- if self.finalized:
- raise FinalizeError
- self._wb_sdram_ifs.append(interface)
-
- def register_sdram_phy(self, phy):
- if self._sdram_phy_registered:
- raise FinalizeError
- self._sdram_phy_registered = True
-
- # Core
- self.submodules.sdram = SDRAMCore(phy,
- phy.module.geom_settings,
- phy.module.timing_settings,
- self.sdram_controller_settings)
-
- dfi_databits_divisor = 1 if phy.settings.memtype == "SDR" else 2
- sdram_width = phy.settings.dfi_databits//dfi_databits_divisor
- main_ram_size = 2**(phy.module.geom_settings.bankbits +
- phy.module.geom_settings.rowbits +
- phy.module.geom_settings.colbits)*sdram_width//8
- # XXX: Limit main_ram_size to 256MB, we should modify mem_map to allow larger memories.
- main_ram_size = min(main_ram_size, 256*1024*1024)
- l2_size = self.sdram_controller_settings.l2_size
- if l2_size:
- self.add_constant("L2_SIZE", l2_size)
-
- # add a Wishbone interface to the DRAM
- wb_sdram = wishbone.Interface()
- self.add_wb_sdram_if(wb_sdram)
- self.register_mem("main_ram", self.mem_map["main_ram"], wb_sdram, main_ram_size)
-
- # LASMICON frontend
- if isinstance(self.sdram_controller_settings, LASMIconSettings):
- if self.sdram_controller_settings.with_bandwidth:
- self.sdram.controller.multiplexer.add_bandwidth()
-
- if self.sdram_controller_settings.with_memtest:
- self.submodules.memtest_w = memtest.MemtestWriter(self.sdram.crossbar.get_master())
- self.submodules.memtest_r = memtest.MemtestReader(self.sdram.crossbar.get_master())
-
- if l2_size:
- lasmim = self.sdram.crossbar.get_master()
- l2_cache = wishbone.Cache(l2_size//4, self._wb_sdram, wishbone.Interface(lasmim.dw))
- # XXX Vivado ->2015.1 workaround, Vivado is not able to map correctly our L2 cache.
- # Issue is reported to Xilinx and should be fixed in next releases (2015.2?).
- # Remove this workaround when fixed by Xilinx.
- from mibuild.xilinx.vivado import XilinxVivadoToolchain
- if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
- from migen.fhdl.simplify import FullMemoryWE
- self.submodules.l2_cache = FullMemoryWE()(l2_cache)
- else:
- self.submodules.l2_cache = l2_cache
- self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(self.l2_cache.slave, lasmim)
-
- # MINICON frontend
- elif isinstance(self.sdram_controller_settings, MiniconSettings):
- if l2_size:
- l2_cache = wishbone.Cache(l2_size//4, self._wb_sdram, self.sdram.controller.bus)
- # XXX Vivado ->2015.1 workaround, Vivado is not able to map correctly our L2 cache.
- # Issue is reported to Xilinx and should be fixed in next releases (2015.2?).
- # Remove this workaround when fixed by Xilinx.
- from mibuild.xilinx.vivado import XilinxVivadoToolchain
- if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
- from migen.fhdl.simplify import FullMemoryWE
- self.submodules.l2_cache = FullMemoryWE()(l2_cache)
- else:
- self.submodules.l2_cache = l2_cache
- else:
- self.submodules.converter = wishbone.Converter(self._wb_sdram, self.sdram.controller.bus)
-
- def do_finalize(self):
- if not self.integrated_main_ram_size:
- if not self._sdram_phy_registered:
- raise FinalizeError("Need to call SDRAMSoC.register_sdram_phy()")
-
- # arbitrate wishbone interfaces to the DRAM
- self.submodules.wb_sdram_con = wishbone.Arbiter(self._wb_sdram_ifs,
- self._wb_sdram)
- SoC.do_finalize(self)
--- /dev/null
+from misoc.spi.core import SPIMaster
--- /dev/null
+from migen import *
+from migen.bank.description import *
+from migen.genlib.fsm import FSM, NextState
+
+
+class SPIMaster(Module, AutoCSR):
+ def __init__(self, pads, width=24, div=2, cpha=1):
+ self.pads = pads
+
+ self._ctrl = CSR()
+ self._length = CSRStorage(8)
+ self._status = CSRStatus()
+ if hasattr(pads, "mosi"):
+ self._mosi = CSRStorage(width)
+ if hasattr(pads, "miso"):
+ self._miso = CSRStatus(width)
+
+ self.irq = Signal()
+
+ ###
+
+ # ctrl
+ start = Signal()
+ length = self._length.storage
+ enable_cs = Signal()
+ enable_shift = Signal()
+ done = Signal()
+
+ self.comb += [
+ start.eq(self._ctrl.re & self._ctrl.r[0]),
+ self._status.status.eq(done)
+ ]
+
+ # clk
+ i = Signal(max=div)
+ set_clk = Signal()
+ clr_clk = Signal()
+ self.sync += [
+ If(set_clk,
+ pads.clk.eq(enable_cs)
+ ),
+ If(clr_clk,
+ pads.clk.eq(0),
+ i.eq(0)
+ ).Else(
+ i.eq(i + 1),
+ )
+ ]
+
+ self.comb += [
+ set_clk.eq(i == (div//2-1)),
+ clr_clk.eq(i == (div-1))
+ ]
+
+ # fsm
+ cnt = Signal(8)
+ 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",
+ If(start,
+ NextState("WAIT_CLK")
+ ),
+ done.eq(1),
+ clr_cnt.eq(1)
+ )
+ fsm.act("WAIT_CLK",
+ If(clr_clk,
+ NextState("SHIFT")
+ ),
+ )
+ fsm.act("SHIFT",
+ If(cnt == length,
+ NextState("END")
+ ).Else(
+ inc_cnt.eq(clr_clk),
+ ),
+ enable_cs.eq(1),
+ enable_shift.eq(1),
+ )
+ fsm.act("END",
+ If(set_clk,
+ NextState("IDLE")
+ ),
+ enable_shift.eq(1),
+ self.irq.eq(1)
+ )
+
+ # miso
+ if hasattr(pads, "miso"):
+ miso = Signal()
+ sr_miso = Signal(width)
+
+ # (cpha = 1: capture on clk falling edge)
+ if cpha:
+ self.sync += \
+ If(enable_shift,
+ If(clr_clk,
+ miso.eq(pads.miso),
+ ).Elif(set_clk,
+ sr_miso.eq(Cat(miso, sr_miso[:-1]))
+ )
+ )
+ # (cpha = 0: capture on clk rising edge)
+ else:
+ self.sync += \
+ If(enable_shift,
+ If(set_clk,
+ miso.eq(pads.miso),
+ ).Elif(clr_clk,
+ sr_miso.eq(Cat(miso, sr_miso[:-1]))
+ )
+ )
+ self.comb += self._miso.status.eq(sr_miso)
+
+ # mosi
+ if hasattr(pads, "mosi"):
+ sr_mosi = Signal(width)
+
+ # (cpha = 1: propagated on clk rising edge)
+ if cpha:
+ self.sync += \
+ If(start,
+ sr_mosi.eq(self._mosi.storage)
+ ).Elif(clr_clk & enable_shift,
+ sr_mosi.eq(Cat(Signal(), sr_mosi[:-1]))
+ ).Elif(set_clk,
+ pads.mosi.eq(sr_mosi[-1])
+ )
+
+ # (cpha = 0: propagated on clk falling edge)
+ else:
+ self.sync += [
+ If(start,
+ sr_mosi.eq(self._mosi.storage)
+ ).Elif(set_clk & enable_shift,
+ sr_mosi.eq(Cat(Signal(), sr_mosi[:-1]))
+ ).Elif(clr_clk,
+ pads.mosi.eq(sr_mosi[-1])
+ )
+ ]
+
+ # cs_n
+ self.comb += pads.cs_n.eq(~enable_cs)
--- /dev/null
+from migen import *
+from migen.genlib.record import *
+from migen.sim.generic import run_simulation
+
+from misoc.com.spi import SPIMaster
+
+
+class SPISlave(Module):
+ def __init__(self, pads, width):
+ self.pads = pads
+ self.width = width
+
+ ###
+
+ self.mosi = 0
+ self.miso = 0
+
+ self.last_cs_n = 1
+ self.last_clk = 0
+
+
+ def get_mosi(self):
+ return self.mosi
+
+ def set_miso(self, value):
+ self.miso = value
+
+ def do_simulation(self, selfp):
+ # detect edges
+ cs_n_rising = 0
+ cs_n_falling = 0
+ clk_rising = 0
+ clk_falling = 0
+ if selfp.pads.cs_n and not self.last_cs_n:
+ cs_n_rising = 1
+ if not selfp.pads.cs_n and self.last_cs_n:
+ cs_n_falling = 1
+ if selfp.pads.clk and not self.last_clk:
+ clk_rising = 1
+ if not selfp.pads.clk and self.last_clk:
+ clk_falling = 1
+
+ # input mosi
+ if clk_falling and not selfp.pads.cs_n:
+ self.mosi = self.mosi << 1
+ self.mosi |= selfp.pads.mosi
+
+ # output miso
+ if (clk_rising and not selfp.pads.cs_n):
+ selfp.pads.miso = (self.miso >> (self.width-1)) & 0x1
+ self.miso = self.miso << 1
+
+ # save signal states
+ self.last_cs_n = selfp.pads.cs_n
+ self.last_clk = selfp.pads.clk
+
+
+def spi_access(selfp, length, mosi):
+ selfp.spi_master._mosi.storage = mosi
+ yield
+ selfp.spi_master._ctrl.r = (length << 8) | 1
+ selfp.spi_master._ctrl.re = 1
+ yield
+ selfp.spi_master._ctrl.r = 0
+ selfp.spi_master._ctrl.re = 0
+ yield
+ while not (selfp.spi_master._status.status & 0x1):
+ yield
+
+
+class TB(Module):
+ def __init__(self):
+ pads = Record([("cs_n", 1), ("clk", 1), ("mosi", 1), ("miso", 1)])
+ self.submodules.spi_master = SPIMaster(pads, 24, 4)
+ self.submodules.spi_slave = SPISlave(pads, 24)
+
+ def gen_simulation(self, selfp):
+ for i in range(16):
+ yield
+ self.spi_slave.set_miso(0x123457)
+ yield from spi_access(selfp, 8, 0x123457)
+ print("{:08x}".format(self.spi_slave.get_mosi()))
+ print("{:08x}".format(selfp.spi_master._miso.status))
+
+if __name__ == "__main__":
+ run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True)
--- /dev/null
+from migen import *
+from migen.bus.transactions import *
+from migen.bus import wishbone
+from migen.genlib.misc import timeline
+from migen.genlib.record import Record
+from migen.bank.description import AutoCSR, CSRStorage, CSRStatus
+
+_FAST_READ = 0x0b
+_DIOFR = 0xbb
+_QIOFR = 0xeb
+
+
+def _format_cmd(cmd, spi_width):
+ """
+ `cmd` is the read instruction. Since everything is transmitted on all
+ dq lines (cmd, adr and data), extend/interleave cmd to full pads.dq
+ width even if dq1-dq3 are don't care during the command phase:
+ For example, for N25Q128, 0xeb is the quad i/o fast read, and
+ extended to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff
+ """
+ c = 2**(8*spi_width)-1
+ for b in range(8):
+ if not (cmd>>b)%2:
+ c &= ~(1<<(b*spi_width))
+ return c
+
+
+class SpiFlash(Module, AutoCSR):
+ def __init__(self, pads, dummy=15, div=2, with_bitbang=True):
+ """
+ Simple SPI flash, e.g. N25Q128 on the LX9 Microboard.
+
+ Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
+ Read). Only supports mode0 (cpol=0, cpha=0).
+ Optionally supports software bitbanging (for write, erase, or other commands).
+ """
+ self.bus = bus = wishbone.Interface()
+ spi_width = flen(pads.dq)
+ if with_bitbang:
+ self.bitbang = CSRStorage(4)
+ self.miso = CSRStatus()
+ self.bitbang_en = CSRStorage()
+
+ ###
+
+ cs_n = Signal(reset=1)
+ clk = Signal()
+ dq_oe = Signal()
+ wbone_width = flen(bus.dat_r)
+
+
+ read_cmd_params = {
+ 4: (_format_cmd(_QIOFR, 4), 4*8),
+ 2: (_format_cmd(_DIOFR, 2), 2*8),
+ 1: (_format_cmd(_FAST_READ, 1), 1*8)
+ }
+ read_cmd, cmd_width = read_cmd_params[spi_width]
+ addr_width = 24
+
+ pads.cs_n.reset = 1
+
+ dq = TSTriple(spi_width)
+ self.specials.dq = dq.get_tristate(pads.dq)
+
+ sr = Signal(max(cmd_width, addr_width, wbone_width))
+ dqs = Replicate(1, spi_width-1)
+
+ self.comb += bus.dat_r.eq(sr)
+
+ hw_read_logic = [
+ pads.clk.eq(clk),
+ pads.cs_n.eq(cs_n),
+ dq.o.eq(sr[-spi_width:]),
+ dq.oe.eq(dq_oe)
+ ]
+
+ if with_bitbang:
+ bitbang_logic = [
+ pads.clk.eq(self.bitbang.storage[1]),
+ pads.cs_n.eq(self.bitbang.storage[2]),
+ dq.o.eq(Cat(self.bitbang.storage[0], dqs)),
+ If(self.bitbang.storage[3],
+ dq.oe.eq(0)
+ ).Else(
+ dq.oe.eq(1)
+ ),
+ If(self.bitbang.storage[1],
+ self.miso.status.eq(dq.i[1])
+ )
+ ]
+
+ self.comb += \
+ If(self.bitbang_en.storage,
+ bitbang_logic
+ ).Else(
+ hw_read_logic
+ )
+ else:
+ self.comb += hw_read_logic
+
+ if div < 2:
+ raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
+ else:
+ i = Signal(max=div)
+ dqi = Signal(spi_width)
+ self.sync += [
+ If(i == div//2 - 1,
+ clk.eq(1),
+ dqi.eq(dq.i),
+ ),
+ If(i == div - 1,
+ i.eq(0),
+ clk.eq(0),
+ sr.eq(Cat(dqi, sr[:-spi_width]))
+ ).Else(
+ i.eq(i + 1),
+ ),
+ ]
+
+ # spi is byte-addressed, prefix by zeros
+ z = Replicate(0, log2_int(wbone_width//8))
+
+ seq = [
+ (cmd_width//spi_width*div,
+ [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]),
+ (addr_width//spi_width*div,
+ [sr[-addr_width:].eq(Cat(z, bus.adr))]),
+ ((dummy + wbone_width//spi_width)*div,
+ [dq_oe.eq(0)]),
+ (1,
+ [bus.ack.eq(1), cs_n.eq(1)]),
+ (div, # tSHSL!
+ [bus.ack.eq(0)]),
+ (0,
+ []),
+ ]
+
+ # accumulate timeline deltas
+ t, tseq = 0, []
+ for dt, a in seq:
+ tseq.append((t, a))
+ t += dt
+
+ self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
+
+
+class SpiFlashTB(Module):
+ def __init__(self):
+ self.submodules.master = wishbone.Initiator(self.gen_reads())
+ self.pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)])
+ self.submodules.slave = SpiFlash(self.pads)
+ self.submodules.tap = wishbone.Tap(self.slave.bus)
+ self.submodules.intercon = wishbone.InterconnectPointToPoint(
+ self.master.bus, self.slave.bus)
+ self.cycle = 0
+
+ def gen_reads(self):
+ for a in range(10):
+ t = TRead(a)
+ yield t
+ print("read {} in {} cycles(s)".format(t.data, t.latency))
+
+ def do_simulation(self, selfp):
+ if selfp.pads.cs_n:
+ self.cycle = 0
+ else:
+ self.cycle += 1
+ if not selfp.slave.dq.oe:
+ selfp.slave.dq.i = self.cycle & 0xf
+ do_simulation.passive = True
+
+if __name__ == "__main__":
+ from migen.sim.generic import run_simulation
+ from migen.fhdl import verilog
+
+ pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)])
+ s = SpiFlash(pads)
+ print(verilog.convert(s, ios={pads.clk, pads.cs_n, pads.dq, s.bus.adr,
+ s.bus.dat_r, s.bus.cyc, s.bus.ack, s.bus.stb}))
+
+ run_simulation(SpiFlashTB(), vcd_name="spiflash.vcd")
--- /dev/null
+from migen import *
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+
+
+class Timer(Module, AutoCSR):
+ def __init__(self, width=32):
+ self._load = CSRStorage(width)
+ self._reload = CSRStorage(width)
+ self._en = CSRStorage()
+ self._update_value = CSR()
+ self._value = CSRStatus(width)
+
+ self.submodules.ev = EventManager()
+ self.ev.zero = EventSourceProcess()
+ self.ev.finalize()
+
+ ###
+
+ value = Signal(width)
+ self.sync += [
+ If(self._en.storage,
+ If(value == 0,
+ # set reload to 0 to disable reloading
+ value.eq(self._reload.storage)
+ ).Else(
+ value.eq(value - 1)
+ )
+ ).Else(
+ value.eq(self._load.storage)
+ ),
+ If(self._update_value.re, self._value.status.eq(value))
+ ]
+ self.comb += self.ev.zero.trigger.eq(value != 0)
+++ /dev/null
-from migen import *
-from migen.bus import wishbone
-from migen.genlib.misc import chooser, Counter, WaitTimer
-from migen.genlib.record import Record
-from migen.genlib.fsm import FSM, NextState
-from migen.flow.actor import Sink, Source
-
-
-class WishboneStreamingBridge(Module):
- cmds = {
- "write": 0x01,
- "read": 0x02
- }
-
- def __init__(self, phy, clk_freq):
- self.wishbone = wishbone.Interface()
-
- # # #
-
- byte_counter = Counter(3)
- word_counter = Counter(8)
- self.submodules += byte_counter, word_counter
-
- cmd = Signal(8)
- cmd_ce = Signal()
-
- length = Signal(8)
- length_ce = Signal()
-
- address = Signal(32)
- address_ce = Signal()
-
- data = Signal(32)
- rx_data_ce = Signal()
- tx_data_ce = Signal()
-
- self.sync += [
- If(cmd_ce, cmd.eq(phy.source.data)),
- If(length_ce, length.eq(phy.source.data)),
- If(address_ce, address.eq(Cat(phy.source.data, address[0:24]))),
- If(rx_data_ce,
- data.eq(Cat(phy.source.data, data[0:24]))
- ).Elif(tx_data_ce,
- data.eq(self.wishbone.dat_r)
- )
- ]
-
- fsm = InsertReset(FSM(reset_state="IDLE"))
- timer = WaitTimer(clk_freq//10)
- self.submodules += fsm, timer
- self.comb += [
- fsm.reset.eq(timer.done),
- phy.source.ack.eq(1)
- ]
- fsm.act("IDLE",
- If(phy.source.stb,
- cmd_ce.eq(1),
- If((phy.source.data == self.cmds["write"]) |
- (phy.source.data == self.cmds["read"]),
- NextState("RECEIVE_LENGTH")
- ),
- byte_counter.reset.eq(1),
- word_counter.reset.eq(1)
- )
- )
- fsm.act("RECEIVE_LENGTH",
- If(phy.source.stb,
- length_ce.eq(1),
- NextState("RECEIVE_ADDRESS")
- )
- )
- fsm.act("RECEIVE_ADDRESS",
- If(phy.source.stb,
- address_ce.eq(1),
- byte_counter.ce.eq(1),
- If(byte_counter.value == 3,
- If(cmd == self.cmds["write"],
- NextState("RECEIVE_DATA")
- ).Elif(cmd == self.cmds["read"],
- NextState("READ_DATA")
- ),
- byte_counter.reset.eq(1),
- )
- )
- )
- fsm.act("RECEIVE_DATA",
- If(phy.source.stb,
- rx_data_ce.eq(1),
- byte_counter.ce.eq(1),
- If(byte_counter.value == 3,
- NextState("WRITE_DATA"),
- byte_counter.reset.eq(1)
- )
- )
- )
- self.comb += [
- self.wishbone.adr.eq(address + word_counter.value),
- self.wishbone.dat_w.eq(data),
- self.wishbone.sel.eq(2**flen(self.wishbone.sel)-1)
- ]
- fsm.act("WRITE_DATA",
- self.wishbone.stb.eq(1),
- self.wishbone.we.eq(1),
- self.wishbone.cyc.eq(1),
- If(self.wishbone.ack,
- word_counter.ce.eq(1),
- If(word_counter.value == (length-1),
- NextState("IDLE")
- ).Else(
- NextState("RECEIVE_DATA")
- )
- )
- )
- fsm.act("READ_DATA",
- self.wishbone.stb.eq(1),
- self.wishbone.we.eq(0),
- self.wishbone.cyc.eq(1),
- If(self.wishbone.ack,
- tx_data_ce.eq(1),
- NextState("SEND_DATA")
- )
- )
- self.comb += \
- chooser(data, byte_counter.value, phy.sink.data, n=4, reverse=True)
- fsm.act("SEND_DATA",
- phy.sink.stb.eq(1),
- If(phy.sink.ack,
- byte_counter.ce.eq(1),
- If(byte_counter.value == 3,
- word_counter.ce.eq(1),
- If(word_counter.value == (length-1),
- NextState("IDLE")
- ).Else(
- NextState("READ_DATA"),
- byte_counter.reset.eq(1)
- )
- )
- )
- )
-
- self.comb += timer.wait.eq(~fsm.ongoing("IDLE"))
-
- if phy.sink.description.packetized:
- self.comb += [
- phy.sink.sop.eq((byte_counter.value == 0) & (word_counter.value == 0)),
- phy.sink.eop.eq((byte_counter.value == 3) & (word_counter.value == (length-1)))
- ]
- if hasattr(phy.sink, "length"):
- self.comb += phy.sink.length.eq(4*length)
--- /dev/null
+from misoc.uart.core import UART, RS232PHY
--- /dev/null
+from migen import *
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+from migen.genlib.record import Record
+from migen.actorlib.fifo import SyncFIFO, AsyncFIFO
+
+
+class RS232PHYRX(Module):
+ def __init__(self, pads, tuning_word):
+ self.source = Source([("data", 8)])
+
+ ###
+
+ uart_clk_rxen = Signal()
+ phase_accumulator_rx = Signal(32)
+
+ rx = Signal()
+ self.specials += MultiReg(pads.rx, rx)
+ rx_r = Signal()
+ rx_reg = Signal(8)
+ rx_bitcount = Signal(4)
+ rx_busy = Signal()
+ rx_done = self.source.stb
+ rx_data = self.source.data
+ self.sync += [
+ rx_done.eq(0),
+ rx_r.eq(rx),
+ If(~rx_busy,
+ If(~rx & rx_r, # look for start bit
+ rx_busy.eq(1),
+ rx_bitcount.eq(0),
+ )
+ ).Else(
+ If(uart_clk_rxen,
+ rx_bitcount.eq(rx_bitcount + 1),
+ If(rx_bitcount == 0,
+ If(rx, # verify start bit
+ rx_busy.eq(0)
+ )
+ ).Elif(rx_bitcount == 9,
+ rx_busy.eq(0),
+ If(rx, # verify stop bit
+ rx_data.eq(rx_reg),
+ rx_done.eq(1)
+ )
+ ).Else(
+ rx_reg.eq(Cat(rx_reg[1:], rx))
+ )
+ )
+ )
+ ]
+ self.sync += \
+ If(rx_busy,
+ Cat(phase_accumulator_rx, uart_clk_rxen).eq(phase_accumulator_rx + tuning_word)
+ ).Else(
+ Cat(phase_accumulator_rx, uart_clk_rxen).eq(2**31)
+ )
+
+
+class RS232PHYTX(Module):
+ def __init__(self, pads, tuning_word):
+ self.sink = Sink([("data", 8)])
+
+ # # #
+
+ uart_clk_txen = Signal()
+ phase_accumulator_tx = Signal(32)
+
+ pads.tx.reset = 1
+
+ tx_reg = Signal(8)
+ tx_bitcount = Signal(4)
+ tx_busy = Signal()
+ self.sync += [
+ self.sink.ack.eq(0),
+ If(self.sink.stb & ~tx_busy & ~self.sink.ack,
+ tx_reg.eq(self.sink.data),
+ tx_bitcount.eq(0),
+ tx_busy.eq(1),
+ pads.tx.eq(0)
+ ).Elif(uart_clk_txen & tx_busy,
+ tx_bitcount.eq(tx_bitcount + 1),
+ If(tx_bitcount == 8,
+ pads.tx.eq(1)
+ ).Elif(tx_bitcount == 9,
+ pads.tx.eq(1),
+ tx_busy.eq(0),
+ self.sink.ack.eq(1),
+ ).Else(
+ pads.tx.eq(tx_reg[0]),
+ tx_reg.eq(Cat(tx_reg[1:], 0))
+ )
+ )
+ ]
+ self.sync += [
+ If(tx_busy,
+ Cat(phase_accumulator_tx, uart_clk_txen).eq(phase_accumulator_tx + tuning_word)
+ ).Else(
+ Cat(phase_accumulator_tx, uart_clk_txen).eq(0)
+ )
+ ]
+
+
+class RS232PHY(Module, AutoCSR):
+ def __init__(self, pads, clk_freq, baudrate=115200):
+ self._tuning_word = CSRStorage(32, reset=int((baudrate/clk_freq)*2**32))
+ self.submodules.tx = RS232PHYTX(pads, self._tuning_word.storage)
+ self.submodules.rx = RS232PHYRX(pads, self._tuning_word.storage)
+ self.sink, self.source = self.tx.sink, self.rx.source
+
+
+def _get_uart_fifo(depth, sink_cd="sys", source_cd="sys"):
+ if sink_cd != source_cd:
+ fifo = AsyncFIFO([("data", 8)], depth)
+ return ClockDomainsRenamer({"write": sink_cd, "read": source_cd})(fifo)
+ else:
+ return SyncFIFO([("data", 8)], depth)
+
+
+class UART(Module, AutoCSR):
+ def __init__(self, phy,
+ tx_fifo_depth=16,
+ rx_fifo_depth=16,
+ phy_cd="sys"):
+ self._rxtx = CSR(8)
+ self._txfull = CSRStatus()
+ self._rxempty = CSRStatus()
+
+ self.submodules.ev = EventManager()
+ self.ev.tx = EventSourceProcess()
+ self.ev.rx = EventSourceProcess()
+ self.ev.finalize()
+
+ # # #
+
+ # TX
+ tx_fifo = _get_uart_fifo(tx_fifo_depth, source_cd=phy_cd)
+ self.submodules += tx_fifo
+
+ self.comb += [
+ tx_fifo.sink.stb.eq(self._rxtx.re),
+ tx_fifo.sink.data.eq(self._rxtx.r),
+ self._txfull.status.eq(~tx_fifo.sink.ack),
+ Record.connect(tx_fifo.source, phy.sink),
+ # Generate TX IRQ when tx_fifo becomes non-full
+ self.ev.tx.trigger.eq(~tx_fifo.sink.ack)
+ ]
+
+ # RX
+ rx_fifo = _get_uart_fifo(rx_fifo_depth, sink_cd=phy_cd)
+ self.submodules += rx_fifo
+
+ self.comb += [
+ Record.connect(phy.source, rx_fifo.sink),
+ self._rxempty.status.eq(~rx_fifo.source.stb),
+ self._rxtx.w.eq(rx_fifo.source.data),
+ rx_fifo.source.ack.eq(self.ev.rx.clear),
+ # Generate RX IRQ when tx_fifo becomes non-empty
+ self.ev.rx.trigger.eq(~rx_fifo.source.stb)
+ ]
--- /dev/null
+# XXX Adapt test to new architecture
+class UARTTB(Module):
+ def __init__(self):
+ self.clk_freq = 83333333
+ self.baud = 3000000
+ self.pads = Record([("rx", 1), ("tx", 1)])
+ self.submodules.slave = UART(self.pads, self.clk_freq, self.baud)
+
+ def wait_for(self, ns_time):
+ freq_in_ghz = self.clk_freq/(10**9)
+ period = 1/freq_in_ghz
+ num_loops = int(ns_time/period)
+ for i in range(num_loops+1):
+ yield
+
+ def gen_simulation(self, selfp):
+ baud_in_ghz = self.baud/(10**9)
+ uart_period = int(1/baud_in_ghz)
+ half_uart_period = int(1/(2*baud_in_ghz))
+
+ # Set TX an RX lines idle
+ selfp.pads.tx = 1
+ selfp.pads.rx = 1
+ yield
+
+ # First send a few characters
+
+ tx_string = "01234"
+ print("Sending string: " + tx_string)
+ for c in tx_string:
+ selfp.slave._r_rxtx.r = ord(c)
+ selfp.slave._r_rxtx.re = 1
+ yield
+ selfp.slave._r_rxtx.re = 0
+
+ yield from self.wait_for(half_uart_period)
+
+ if selfp.pads.tx:
+ print("FAILURE: no start bit sent")
+
+ val = 0
+ for i in range(8):
+ yield from self.wait_for(uart_period)
+ val >>= 1
+ if selfp.pads.tx:
+ val |= 0x80
+
+ yield from self.wait_for(uart_period)
+
+ if selfp.pads.tx == 0:
+ print("FAILURE: no stop bit sent")
+
+ if ord(c) != val:
+ print("FAILURE: sent decimal value "+str(val)+" (char "+chr(val)+") instead of "+c)
+ else:
+ print("SUCCESS: sent "+c)
+ while selfp.slave.ev.tx.trigger != 1:
+ yield
+
+ # Then receive a character
+
+ rx_string = '5'
+ print("Receiving character "+rx_string)
+ rx_value = ord(rx_string)
+ for i in range(11):
+ if (i == 0):
+ # start bit
+ selfp.pads.rx = 0
+ elif (i == 9):
+ # stop bit
+ selfp.pads.rx = 1
+ elif (i == 10):
+ selfp.pads.rx = 1
+ break
+ else:
+ selfp.pads.rx = 1 if (rx_value & 1) else 0
+ rx_value >>= 1
+ yield from self.wait_for(uart_period)
+
+ rx_value = ord(rx_string)
+ received_value = selfp.slave._r_rxtx.w
+ if (received_value == rx_value):
+ print("RX SUCCESS: ")
+ else:
+ print("RX FAILURE: ")
+
+ print("received "+chr(received_value))
+
+ while True:
+ yield
+
+if __name__ == "__main__":
+ from migen.sim.generic import Simulator, TopLevel
+ from migen.sim import icarus
+ with Simulator(UARTTB(), TopLevel("top.vcd", clk_period=int(1/0.08333333)),
+ icarus.Runner(keep_files=False)) as s:
+ s.run(20000)
+++ /dev/null
-from migen import *
-from migen.bank.description import AutoCSR
-
-from misoc.video.dvisampler.edid import EDID
-from misoc.video.dvisampler.clocking import Clocking
-from misoc.video.dvisampler.datacapture import DataCapture
-from misoc.video.dvisampler.charsync import CharSync
-from misoc.video.dvisampler.wer import WER
-from misoc.video.dvisampler.decoding import Decoding
-from misoc.video.dvisampler.chansync import ChanSync
-from misoc.video.dvisampler.analysis import SyncPolarity, ResolutionDetection, FrameExtraction
-from misoc.video.dvisampler.dma import DMA
-
-
-class DVISampler(Module, AutoCSR):
- def __init__(self, pads, lasmim, n_dma_slots=2, fifo_depth=512):
- self.submodules.edid = EDID(pads)
- self.submodules.clocking = Clocking(pads)
-
- for datan in range(3):
- name = "data" + str(datan)
-
- cap = DataCapture(getattr(pads, name + "_p"), getattr(pads, name + "_n"), 8)
- setattr(self.submodules, name + "_cap", cap)
- self.comb += cap.serdesstrobe.eq(self.clocking.serdesstrobe)
-
- charsync = CharSync()
- setattr(self.submodules, name + "_charsync", charsync)
- self.comb += charsync.raw_data.eq(cap.d)
-
- wer = WER()
- setattr(self.submodules, name + "_wer", wer)
- self.comb += wer.data.eq(charsync.data)
-
- decoding = Decoding()
- setattr(self.submodules, name + "_decod", decoding)
- self.comb += [
- decoding.valid_i.eq(charsync.synced),
- decoding.input.eq(charsync.data)
- ]
-
- self.submodules.chansync = ChanSync()
- self.comb += [
- self.chansync.valid_i.eq(self.data0_decod.valid_o & \
- self.data1_decod.valid_o & self.data2_decod.valid_o),
- self.chansync.data_in0.eq(self.data0_decod.output),
- self.chansync.data_in1.eq(self.data1_decod.output),
- self.chansync.data_in2.eq(self.data2_decod.output),
- ]
-
- self.submodules.syncpol = SyncPolarity()
- self.comb += [
- self.syncpol.valid_i.eq(self.chansync.chan_synced),
- self.syncpol.data_in0.eq(self.chansync.data_out0),
- self.syncpol.data_in1.eq(self.chansync.data_out1),
- self.syncpol.data_in2.eq(self.chansync.data_out2)
- ]
-
- self.submodules.resdetection = ResolutionDetection()
- self.comb += [
- self.resdetection.valid_i.eq(self.syncpol.valid_o),
- self.resdetection.de.eq(self.syncpol.de),
- self.resdetection.vsync.eq(self.syncpol.vsync)
- ]
-
- self.submodules.frame = FrameExtraction(24*lasmim.dw//32, fifo_depth)
- self.comb += [
- self.frame.valid_i.eq(self.syncpol.valid_o),
- self.frame.de.eq(self.syncpol.de),
- self.frame.vsync.eq(self.syncpol.vsync),
- self.frame.r.eq(self.syncpol.r),
- self.frame.g.eq(self.syncpol.g),
- self.frame.b.eq(self.syncpol.b)
- ]
-
- self.submodules.dma = DMA(lasmim, n_dma_slots)
- self.comb += self.frame.frame.connect(self.dma.frame)
- self.ev = self.dma.ev
-
- autocsr_exclude = {"ev"}
+++ /dev/null
-from migen import *
-from migen.genlib.cdc import MultiReg, PulseSynchronizer
-from migen.genlib.fifo import AsyncFIFO
-from migen.genlib.record import Record
-from migen.bank.description import *
-from migen.flow.actor import *
-
-from misoc.video.dvisampler.common import channel_layout
-
-
-class SyncPolarity(Module):
- def __init__(self):
- self.valid_i = Signal()
- self.data_in0 = Record(channel_layout)
- self.data_in1 = Record(channel_layout)
- self.data_in2 = Record(channel_layout)
-
- self.valid_o = Signal()
- self.de = Signal()
- self.hsync = Signal()
- self.vsync = Signal()
- self.r = Signal(8)
- self.g = Signal(8)
- self.b = Signal(8)
-
- ###
-
- de = self.data_in0.de
- de_r = Signal()
- c = self.data_in0.c
- c_polarity = Signal(2)
- c_out = Signal(2)
-
- self.comb += [
- self.de.eq(de_r),
- self.hsync.eq(c_out[0]),
- self.vsync.eq(c_out[1])
- ]
-
- self.sync.pix += [
- self.valid_o.eq(self.valid_i),
- self.r.eq(self.data_in2.d),
- self.g.eq(self.data_in1.d),
- self.b.eq(self.data_in0.d),
-
- de_r.eq(de),
- If(de_r & ~de,
- c_polarity.eq(c),
- c_out.eq(0)
- ).Else(
- c_out.eq(c ^ c_polarity)
- )
- ]
-
-
-class ResolutionDetection(Module, AutoCSR):
- def __init__(self, nbits=11):
- self.valid_i = Signal()
- self.vsync = Signal()
- self.de = Signal()
-
- self._hres = CSRStatus(nbits)
- self._vres = CSRStatus(nbits)
-
- ###
-
- # Detect DE transitions
- de_r = Signal()
- pn_de = Signal()
- self.sync.pix += de_r.eq(self.de)
- self.comb += pn_de.eq(~self.de & de_r)
-
- # HRES
- hcounter = Signal(nbits)
- self.sync.pix += If(self.valid_i & self.de,
- hcounter.eq(hcounter + 1)
- ).Else(
- hcounter.eq(0)
- )
-
- hcounter_st = Signal(nbits)
- self.sync.pix += If(self.valid_i,
- If(pn_de, hcounter_st.eq(hcounter))
- ).Else(
- hcounter_st.eq(0)
- )
- self.specials += MultiReg(hcounter_st, self._hres.status)
-
- # VRES
- vsync_r = Signal()
- p_vsync = Signal()
- self.sync.pix += vsync_r.eq(self.vsync),
- self.comb += p_vsync.eq(self.vsync & ~vsync_r)
-
- vcounter = Signal(nbits)
- self.sync.pix += If(self.valid_i & p_vsync,
- vcounter.eq(0)
- ).Elif(pn_de,
- vcounter.eq(vcounter + 1)
- )
-
- vcounter_st = Signal(nbits)
- self.sync.pix += If(self.valid_i,
- If(p_vsync, vcounter_st.eq(vcounter))
- ).Else(
- vcounter_st.eq(0)
- )
- self.specials += MultiReg(vcounter_st, self._vres.status)
-
-
-class FrameExtraction(Module, AutoCSR):
- def __init__(self, word_width, fifo_depth):
- # in pix clock domain
- self.valid_i = Signal()
- self.vsync = Signal()
- self.de = Signal()
- self.r = Signal(8)
- self.g = Signal(8)
- self.b = Signal(8)
-
- # in sys clock domain
- word_layout = [("sof", 1), ("pixels", word_width)]
- self.frame = Source(word_layout)
- self.busy = Signal()
-
- self._overflow = CSR()
-
- ###
-
- # start of frame detection
- vsync_r = Signal()
- new_frame = Signal()
- self.comb += new_frame.eq(self.vsync & ~vsync_r)
- self.sync.pix += vsync_r.eq(self.vsync)
-
- # pack pixels into words
- cur_word = Signal(word_width)
- cur_word_valid = Signal()
- encoded_pixel = Signal(24)
- self.comb += encoded_pixel.eq(Cat(self.b, self.g, self.r))
- pack_factor = word_width//24
- assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
- pack_counter = Signal(max=pack_factor)
- self.sync.pix += [
- cur_word_valid.eq(0),
- If(new_frame,
- cur_word_valid.eq(pack_counter == (pack_factor - 1)),
- pack_counter.eq(0),
- ).Elif(self.valid_i & self.de,
- [If(pack_counter == (pack_factor-i-1),
- cur_word[24*i:24*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)],
- cur_word_valid.eq(pack_counter == (pack_factor - 1)),
- pack_counter.eq(pack_counter + 1)
- )
- ]
-
- # FIFO
- fifo = RenameClockDomains(AsyncFIFO(word_layout, fifo_depth),
- {"write": "pix", "read": "sys"})
- self.submodules += fifo
- self.comb += [
- fifo.din.pixels.eq(cur_word),
- fifo.we.eq(cur_word_valid)
- ]
- self.sync.pix += \
- If(new_frame,
- fifo.din.sof.eq(1)
- ).Elif(cur_word_valid,
- fifo.din.sof.eq(0)
- )
- self.comb += [
- self.frame.stb.eq(fifo.readable),
- self.frame.payload.eq(fifo.dout),
- fifo.re.eq(self.frame.ack),
- self.busy.eq(0)
- ]
-
- # overflow detection
- pix_overflow = Signal()
- pix_overflow_reset = Signal()
- self.sync.pix += [
- If(fifo.we & ~fifo.writable,
- pix_overflow.eq(1)
- ).Elif(pix_overflow_reset,
- pix_overflow.eq(0)
- )
- ]
-
- sys_overflow = Signal()
- self.specials += MultiReg(pix_overflow, sys_overflow)
- self.submodules.overflow_reset = PulseSynchronizer("sys", "pix")
- self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys")
- self.comb += [
- pix_overflow_reset.eq(self.overflow_reset.o),
- self.overflow_reset_ack.i.eq(pix_overflow_reset)
- ]
-
- overflow_mask = Signal()
- self.comb += [
- self._overflow.w.eq(sys_overflow & ~overflow_mask),
- self.overflow_reset.i.eq(self._overflow.re)
- ]
- self.sync += \
- If(self._overflow.re,
- overflow_mask.eq(1)
- ).Elif(self.overflow_reset_ack.o,
- overflow_mask.eq(0)
- )
+++ /dev/null
-from migen import *
-from migen.genlib.cdc import MultiReg
-from migen.genlib.fifo import _inc
-from migen.genlib.record import Record, layout_len
-from migen.genlib.misc import optree
-from migen.bank.description import *
-
-from misoc.video.dvisampler.common import channel_layout
-
-
-class _SyncBuffer(Module):
- def __init__(self, width, depth):
- self.din = Signal(width)
- self.dout = Signal(width)
- self.re = Signal()
-
- ###
-
- produce = Signal(max=depth)
- consume = Signal(max=depth)
- storage = Memory(width, depth)
- self.specials += storage
-
- wrport = storage.get_port(write_capable=True)
- self.specials += wrport
- self.comb += [
- wrport.adr.eq(produce),
- wrport.dat_w.eq(self.din),
- wrport.we.eq(1)
- ]
- self.sync += _inc(produce, depth)
-
- rdport = storage.get_port(async_read=True)
- self.specials += rdport
- self.comb += [
- rdport.adr.eq(consume),
- self.dout.eq(rdport.dat_r)
- ]
- self.sync += If(self.re, _inc(consume, depth))
-
-
-class ChanSync(Module, AutoCSR):
- def __init__(self, nchan=3, depth=8):
- self.valid_i = Signal()
- self.chan_synced = Signal()
-
- self._channels_synced = CSRStatus()
-
- lst_control = []
- all_control = Signal()
- for i in range(nchan):
- name = "data_in" + str(i)
- data_in = Record(channel_layout, name=name)
- setattr(self, name, data_in)
- name = "data_out" + str(i)
- data_out = Record(channel_layout, name=name)
- setattr(self, name, data_out)
-
- ###
-
- syncbuffer = RenameClockDomains(_SyncBuffer(layout_len(channel_layout), depth), "pix")
- self.submodules += syncbuffer
- self.comb += [
- syncbuffer.din.eq(data_in.raw_bits()),
- data_out.raw_bits().eq(syncbuffer.dout)
- ]
- is_control = Signal()
- self.comb += [
- is_control.eq(~data_out.de),
- syncbuffer.re.eq(~is_control | all_control)
- ]
- lst_control.append(is_control)
-
- some_control = Signal()
- self.comb += [
- all_control.eq(optree("&", lst_control)),
- some_control.eq(optree("|", lst_control))
- ]
- self.sync.pix += If(~self.valid_i,
- self.chan_synced.eq(0)
- ).Else(
- If(some_control,
- If(all_control,
- self.chan_synced.eq(1)
- ).Else(
- self.chan_synced.eq(0)
- )
- )
- )
- self.specials += MultiReg(self.chan_synced, self._channels_synced.status)
-
-
-class _TB(Module):
- def __init__(self, test_seq_it):
- self.test_seq_it = test_seq_it
-
- self.submodules.chansync = RenameClockDomains(ChanSync(), {"pix": "sys"})
- self.comb += self.chansync.valid_i.eq(1)
-
- def do_simulation(self, selfp):
- try:
- de0, de1, de2 = next(self.test_seq_it)
- except StopIteration:
- raise StopSimulation
-
- selfp.chansync.data_in0.de = de0
- selfp.chansync.data_in1.de = de1
- selfp.chansync.data_in2.de = de2
- selfp.chansync.data_in0.d = selfp.simulator.cycle_counter
- selfp.chansync.data_in1.d = selfp.simulator.cycle_counter
- selfp.chansync.data_in2.d = selfp.simulator.cycle_counter
-
- out0 = selfp.chansync.data_out0.d
- out1 = selfp.chansync.data_out1.d
- out2 = selfp.chansync.data_out2.d
-
- print("{0:5} {1:5} {2:5}".format(out0, out1, out2))
-
-if __name__ == "__main__":
- from migen.sim.generic import run_simulation
-
- test_seq = [
- (1, 1, 1),
- (1, 1, 0),
- (0, 0, 0),
- (0, 0, 0),
- (0, 0, 1),
- (1, 1, 1),
- (1, 1, 1),
- ]
- tb = _TB(iter(test_seq*2))
- run_simulation(tb)
+++ /dev/null
-from migen import *
-from migen.genlib.cdc import MultiReg
-from migen.genlib.misc import optree
-from migen.bank.description import *
-
-from misoc.video.dvisampler.common import control_tokens
-
-
-class CharSync(Module, AutoCSR):
- def __init__(self, required_controls=8):
- self.raw_data = Signal(10)
- self.synced = Signal()
- self.data = Signal(10)
-
- self._char_synced = CSRStatus()
- self._ctl_pos = CSRStatus(bits_for(9))
-
- ###
-
- raw_data1 = Signal(10)
- self.sync.pix += raw_data1.eq(self.raw_data)
- raw = Signal(20)
- self.comb += raw.eq(Cat(raw_data1, self.raw_data))
-
- found_control = Signal()
- control_position = Signal(max=10)
- self.sync.pix += found_control.eq(0)
- for i in range(10):
- self.sync.pix += If(optree("|", [raw[i:i+10] == t for t in control_tokens]),
- found_control.eq(1),
- control_position.eq(i)
- )
-
- control_counter = Signal(max=required_controls)
- previous_control_position = Signal(max=10)
- word_sel = Signal(max=10)
- self.sync.pix += [
- If(found_control & (control_position == previous_control_position),
- If(control_counter == (required_controls - 1),
- control_counter.eq(0),
- self.synced.eq(1),
- word_sel.eq(control_position)
- ).Else(
- control_counter.eq(control_counter + 1)
- )
- ).Else(
- control_counter.eq(0)
- ),
- previous_control_position.eq(control_position)
- ]
- self.specials += MultiReg(self.synced, self._char_synced.status)
- self.specials += MultiReg(word_sel, self._ctl_pos.status)
-
- self.sync.pix += self.data.eq(raw >> word_sel)
+++ /dev/null
-from migen import *
-from migen.genlib.cdc import MultiReg
-from migen.bank.description import *
-
-
-class Clocking(Module, AutoCSR):
- def __init__(self, pads):
- self._pll_reset = CSRStorage(reset=1)
- self._locked = CSRStatus()
-
- # DRP
- self._pll_adr = CSRStorage(5)
- self._pll_dat_r = CSRStatus(16)
- self._pll_dat_w = CSRStorage(16)
- self._pll_read = CSR()
- self._pll_write = CSR()
- self._pll_drdy = CSRStatus()
-
- self.locked = Signal()
- self.serdesstrobe = Signal()
- self.clock_domains._cd_pix = ClockDomain()
- self.clock_domains._cd_pix2x = ClockDomain()
- self.clock_domains._cd_pix10x = ClockDomain(reset_less=True)
-
- ###
-
- clk_se = Signal()
- self.specials += Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_se)
-
- clkfbout = Signal()
- pll_locked = Signal()
- pll_clk0 = Signal()
- pll_clk1 = Signal()
- pll_clk2 = Signal()
- pll_drdy = Signal()
- self.sync += If(self._pll_read.re | self._pll_write.re,
- self._pll_drdy.status.eq(0)
- ).Elif(pll_drdy,
- self._pll_drdy.status.eq(1)
- )
- self.specials += Instance("PLL_ADV",
- p_CLKFBOUT_MULT=10,
- p_CLKOUT0_DIVIDE=1, # pix10x
- p_CLKOUT1_DIVIDE=5, # pix2x
- p_CLKOUT2_DIVIDE=10, # pix
- p_COMPENSATION="INTERNAL",
-
- i_CLKINSEL=1,
- i_CLKIN1=clk_se,
- o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
- o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
- o_LOCKED=pll_locked, i_RST=self._pll_reset.storage,
-
- i_DADDR=self._pll_adr.storage,
- o_DO=self._pll_dat_r.status,
- i_DI=self._pll_dat_w.storage,
- i_DEN=self._pll_read.re | self._pll_write.re,
- i_DWE=self._pll_write.re,
- o_DRDY=pll_drdy,
- i_DCLK=ClockSignal())
-
- locked_async = Signal()
- self.specials += [
- Instance("BUFPLL", p_DIVIDE=5,
- i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked,
- o_IOCLK=self._cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
- Instance("BUFG", i_I=pll_clk1, o_O=self._cd_pix2x.clk),
- Instance("BUFG", i_I=pll_clk2, o_O=self._cd_pix.clk),
- MultiReg(locked_async, self.locked, "sys")
- ]
- self.comb += self._locked.status.eq(self.locked)
-
- # sychronize pix+pix2x reset
- pix_rst_n = 1
- for i in range(2):
- new_pix_rst_n = Signal()
- self.specials += Instance("FDCE", i_D=pix_rst_n, i_CE=1, i_C=ClockSignal("pix"),
- i_CLR=~locked_async, o_Q=new_pix_rst_n)
- pix_rst_n = new_pix_rst_n
- self.comb += self._cd_pix.rst.eq(~pix_rst_n), self._cd_pix2x.rst.eq(~pix_rst_n)
+++ /dev/null
-control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
-channel_layout = [("d", 8), ("c", 2), ("de", 1)]
+++ /dev/null
-from migen import *
-from migen.genlib.cdc import MultiReg, PulseSynchronizer
-from migen.bank.description import *
-
-
-class DataCapture(Module, AutoCSR):
- def __init__(self, pad_p, pad_n, ntbits):
- self.serdesstrobe = Signal()
- self.d = Signal(10)
-
- self._dly_ctl = CSR(6)
- self._dly_busy = CSRStatus(2)
- self._phase = CSRStatus(2)
- self._phase_reset = CSR()
-
- ###
-
- # IO
- pad_se = Signal()
- self.specials += Instance("IBUFDS", i_I=pad_p, i_IB=pad_n, o_O=pad_se)
-
- pad_delayed_master = Signal()
- pad_delayed_slave = Signal()
- delay_inc = Signal()
- delay_ce = Signal()
- delay_master_cal = Signal()
- delay_master_rst = Signal()
- delay_master_busy = Signal()
- delay_slave_cal = Signal()
- delay_slave_rst = Signal()
- delay_slave_busy = Signal()
- self.specials += Instance("IODELAY2",
- p_SERDES_MODE="MASTER",
- p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
- p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR",
-
- i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_master,
- i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"),
-
- i_INC=delay_inc, i_CE=delay_ce,
- i_CAL=delay_master_cal, i_RST=delay_master_rst, o_BUSY=delay_master_busy,
- i_T=1)
- self.specials += Instance("IODELAY2",
- p_SERDES_MODE="SLAVE",
- p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
- p_COUNTER_WRAPAROUND="WRAPAROUND", p_DATA_RATE="SDR",
-
- i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_slave,
- i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"),
-
- i_INC=delay_inc, i_CE=delay_ce,
- i_CAL=delay_slave_cal, i_RST=delay_slave_rst, o_BUSY=delay_slave_busy,
- i_T=1)
-
- dsr2 = Signal(5)
- pd_valid = Signal()
- pd_incdec = Signal()
- pd_edge = Signal()
- pd_cascade = Signal()
- self.specials += Instance("ISERDES2",
- p_SERDES_MODE="MASTER",
- p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5,
- p_INTERFACE_TYPE="RETIMED",
-
- i_D=pad_delayed_master,
- o_Q4=dsr2[4], o_Q3=dsr2[3], o_Q2=dsr2[2], o_Q1=dsr2[1],
-
- i_BITSLIP=0, i_CE0=1, i_RST=0,
- i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"),
- i_IOCE=self.serdesstrobe,
-
- o_VALID=pd_valid, o_INCDEC=pd_incdec,
- i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade)
- self.specials += Instance("ISERDES2",
- p_SERDES_MODE="SLAVE",
- p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5,
- p_INTERFACE_TYPE="RETIMED",
-
- i_D=pad_delayed_slave,
- o_Q4=dsr2[0],
-
- i_BITSLIP=0, i_CE0=1, i_RST=0,
- i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"),
- i_IOCE=self.serdesstrobe,
-
- i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge)
-
- # Phase error accumulator
- lateness = Signal(ntbits, reset=2**(ntbits - 1))
- too_late = Signal()
- too_early = Signal()
- reset_lateness = Signal()
- self.comb += [
- too_late.eq(lateness == (2**ntbits - 1)),
- too_early.eq(lateness == 0)
- ]
- self.sync.pix2x += [
- If(reset_lateness,
- lateness.eq(2**(ntbits - 1))
- ).Elif(~delay_master_busy & ~delay_slave_busy & ~too_late & ~too_early,
- If(pd_valid & pd_incdec, lateness.eq(lateness - 1)),
- If(pd_valid & ~pd_incdec, lateness.eq(lateness + 1))
- )
- ]
-
- # Delay control
- self.submodules.delay_master_done = PulseSynchronizer("pix2x", "sys")
- delay_master_pending = Signal()
- self.sync.pix2x += [
- self.delay_master_done.i.eq(0),
- If(~delay_master_pending,
- If(delay_master_cal | delay_ce, delay_master_pending.eq(1))
- ).Else(
- If(~delay_master_busy,
- self.delay_master_done.i.eq(1),
- delay_master_pending.eq(0)
- )
- )
- ]
- self.submodules.delay_slave_done = PulseSynchronizer("pix2x", "sys")
- delay_slave_pending = Signal()
- self.sync.pix2x += [
- self.delay_slave_done.i.eq(0),
- If(~delay_slave_pending,
- If(delay_slave_cal | delay_ce, delay_slave_pending.eq(1))
- ).Else(
- If(~delay_slave_busy,
- self.delay_slave_done.i.eq(1),
- delay_slave_pending.eq(0)
- )
- )
- ]
-
- self.submodules.do_delay_master_cal = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_master_rst = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_slave_cal = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_slave_rst = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix2x")
- self.comb += [
- delay_master_cal.eq(self.do_delay_master_cal.o),
- delay_master_rst.eq(self.do_delay_master_rst.o),
- delay_slave_cal.eq(self.do_delay_slave_cal.o),
- delay_slave_rst.eq(self.do_delay_slave_rst.o),
- delay_inc.eq(self.do_delay_inc.o),
- delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o),
- ]
-
- sys_delay_master_pending = Signal()
- self.sync += [
- If(self.do_delay_master_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
- sys_delay_master_pending.eq(1)
- ).Elif(self.delay_master_done.o,
- sys_delay_master_pending.eq(0)
- )
- ]
- sys_delay_slave_pending = Signal()
- self.sync += [
- If(self.do_delay_slave_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
- sys_delay_slave_pending.eq(1)
- ).Elif(self.delay_slave_done.o,
- sys_delay_slave_pending.eq(0)
- )
- ]
-
- self.comb += [
- self.do_delay_master_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[0]),
- self.do_delay_master_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[1]),
- self.do_delay_slave_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[2]),
- self.do_delay_slave_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[3]),
- self.do_delay_inc.i.eq(self._dly_ctl.re & self._dly_ctl.r[4]),
- self.do_delay_dec.i.eq(self._dly_ctl.re & self._dly_ctl.r[5]),
- self._dly_busy.status.eq(Cat(sys_delay_master_pending, sys_delay_slave_pending))
- ]
-
- # Phase detector control
- self.specials += MultiReg(Cat(too_late, too_early), self._phase.status)
- self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix2x")
- self.comb += [
- reset_lateness.eq(self.do_reset_lateness.o),
- self.do_reset_lateness.i.eq(self._phase_reset.re)
- ]
-
- # 5:10 deserialization
- dsr = Signal(10)
- self.sync.pix2x += dsr.eq(Cat(dsr[5:], dsr2))
- self.sync.pix += self.d.eq(dsr)
+++ /dev/null
-from migen import *
-from migen.genlib.fifo import AsyncFIFO
-from migen.genlib.record import layout_len
-from migen.bank.description import AutoCSR
-from migen.actorlib import structuring, spi
-
-from misoc.mem.sdram.frontend import dma_lasmi
-from misoc.video.dvisampler.edid import EDID
-from misoc.video.dvisampler.clocking import Clocking
-from misoc.video.dvisampler.datacapture import DataCapture
-
-
-class RawDVISampler(Module, AutoCSR):
- def __init__(self, pads, asmiport):
- self.submodules.edid = EDID(pads)
- self.submodules.clocking = Clocking(pads)
-
- invert = False
- try:
- s = getattr(pads, "data0")
- except AttributeError:
- s = getattr(pads, "data0_n")
- invert = True
- self.submodules.data0_cap = DataCapture(8, invert)
- self.comb += [
- self.data0_cap.pad.eq(s),
- self.data0_cap.serdesstrobe.eq(self.clocking.serdesstrobe)
- ]
-
- fifo = RenameClockDomains(AsyncFIFO(10, 256),
- {"write": "pix", "read": "sys"})
- self.submodules += fifo
- self.comb += [
- fifo.din.eq(self.data0_cap.d),
- fifo.we.eq(1)
- ]
-
- pack_factor = asmiport.hub.dw//16
- self.submodules.packer = structuring.Pack([("word", 10), ("pad", 6)], pack_factor)
- self.submodules.cast = structuring.Cast(self.packer.source.payload.layout, asmiport.hub.dw)
- self.submodules.dma = spi.DMAWriteController(dma_lasmi.Writer(lasmim), spi.MODE_SINGLE_SHOT)
- self.comb += [
- self.packer.sink.stb.eq(fifo.readable),
- fifo.re.eq(self.packer.sink.ack),
- self.packer.sink.word.eq(fifo.dout),
- self.packer.source.connect_flat(self.cast.sink),
- self.cast.source.connect_flat(self.dma.data)
- ]
+++ /dev/null
-from migen import *
-from migen.genlib.record import Record
-
-from misoc.video.dvisampler.common import control_tokens, channel_layout
-
-
-class Decoding(Module):
- def __init__(self):
- self.valid_i = Signal()
- self.input = Signal(10)
- self.valid_o = Signal()
- self.output = Record(channel_layout)
-
- ###
-
- self.sync.pix += self.output.de.eq(1)
- for i, t in enumerate(control_tokens):
- self.sync.pix += If(self.input == t,
- self.output.de.eq(0),
- self.output.c.eq(i)
- )
- self.sync.pix += self.output.d[0].eq(self.input[0] ^ self.input[9])
- for i in range(1, 8):
- self.sync.pix += self.output.d[i].eq(self.input[i] ^ self.input[i-1] ^ ~self.input[8])
- self.sync.pix += self.valid_o.eq(self.valid_i)
+++ /dev/null
-from migen import *
-from migen.genlib.fsm import FSM, NextState
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-from migen.flow.actor import *
-
-from misoc.mem.sdram.frontend import dma_lasmi
-
-
-# Slot status: EMPTY=0 LOADED=1 PENDING=2
-class _Slot(Module, AutoCSR):
- def __init__(self, addr_bits, alignment_bits):
- self.ev_source = EventSourceLevel()
- self.address = Signal(addr_bits)
- self.address_reached = Signal(addr_bits)
- self.address_valid = Signal()
- self.address_done = Signal()
-
- self._status = CSRStorage(2, write_from_dev=True)
- self._address = CSRStorage(addr_bits + alignment_bits, alignment_bits=alignment_bits, write_from_dev=True)
-
- ###
-
- self.comb += [
- self.address.eq(self._address.storage),
- self.address_valid.eq(self._status.storage[0]),
- self._status.dat_w.eq(2),
- self._status.we.eq(self.address_done),
- self._address.dat_w.eq(self.address_reached),
- self._address.we.eq(self.address_done),
- self.ev_source.trigger.eq(self._status.storage[1])
- ]
-
-
-class _SlotArray(Module, AutoCSR):
- def __init__(self, nslots, addr_bits, alignment_bits):
- self.submodules.ev = EventManager()
- self.address = Signal(addr_bits)
- self.address_reached = Signal(addr_bits)
- self.address_valid = Signal()
- self.address_done = Signal()
-
- ###
-
- slots = [_Slot(addr_bits, alignment_bits) for i in range(nslots)]
- for n, slot in enumerate(slots):
- setattr(self.submodules, "slot"+str(n), slot)
- setattr(self.ev, "slot"+str(n), slot.ev_source)
- self.ev.finalize()
-
- change_slot = Signal()
- current_slot = Signal(max=nslots)
- self.sync += If(change_slot, [If(slot.address_valid, current_slot.eq(n)) for n, slot in reversed(list(enumerate(slots)))])
- self.comb += change_slot.eq(~self.address_valid | self.address_done)
-
- self.comb += [
- self.address.eq(Array(slot.address for slot in slots)[current_slot]),
- self.address_valid.eq(Array(slot.address_valid for slot in slots)[current_slot])
- ]
- self.comb += [slot.address_reached.eq(self.address_reached) for slot in slots]
- self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)]
-
-
-class DMA(Module):
- def __init__(self, lasmim, nslots):
- bus_aw = lasmim.aw
- bus_dw = lasmim.dw
- alignment_bits = bits_for(bus_dw//8) - 1
-
- fifo_word_width = 24*bus_dw//32
- self.frame = Sink([("sof", 1), ("pixels", fifo_word_width)])
- self._frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits)
- self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits)
- self.ev = self._slot_array.ev
-
- ###
-
- # address generator + maximum memory word count to prevent DMA buffer overrun
- reset_words = Signal()
- count_word = Signal()
- last_word = Signal()
- current_address = Signal(bus_aw)
- mwords_remaining = Signal(bus_aw)
- self.comb += [
- self._slot_array.address_reached.eq(current_address),
- last_word.eq(mwords_remaining == 1)
- ]
- self.sync += [
- If(reset_words,
- current_address.eq(self._slot_array.address),
- mwords_remaining.eq(self._frame_size.storage)
- ).Elif(count_word,
- current_address.eq(current_address + 1),
- mwords_remaining.eq(mwords_remaining - 1)
- )
- ]
-
- # 24bpp -> 32bpp
- memory_word = Signal(bus_dw)
- pixbits = []
- for i in range(bus_dw//32):
- for j in range(3):
- b = (i*3+j)*8
- pixbits.append(self.frame.pixels[b+6:b+8])
- pixbits.append(self.frame.pixels[b:b+8])
- pixbits.append(0)
- pixbits.append(0)
- self.comb += memory_word.eq(Cat(*pixbits))
-
- # bus accessor
- self.submodules._bus_accessor = dma_lasmi.Writer(lasmim)
- self.comb += [
- self._bus_accessor.address_data.a.eq(current_address),
- self._bus_accessor.address_data.d.eq(memory_word)
- ]
-
- # control FSM
- fsm = FSM()
- self.submodules += fsm
-
- fsm.act("WAIT_SOF",
- reset_words.eq(1),
- self.frame.ack.eq(~self._slot_array.address_valid | ~self.frame.sof),
- If(self._slot_array.address_valid & self.frame.sof & self.frame.stb, NextState("TRANSFER_PIXELS"))
- )
- fsm.act("TRANSFER_PIXELS",
- self.frame.ack.eq(self._bus_accessor.address_data.ack),
- If(self.frame.stb,
- self._bus_accessor.address_data.stb.eq(1),
- If(self._bus_accessor.address_data.ack,
- count_word.eq(1),
- If(last_word, NextState("EOF"))
- )
- )
- )
- fsm.act("EOF",
- If(~self._bus_accessor.busy,
- self._slot_array.address_done.eq(1),
- NextState("WAIT_SOF")
- )
- )
-
- def get_csrs(self):
- return [self._frame_size] + self._slot_array.get_csrs()
+++ /dev/null
-from migen import *
-from migen.fhdl.specials import Tristate
-from migen.genlib.cdc import MultiReg
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.misc import chooser
-from migen.bank.description import CSRStorage, CSRStatus, AutoCSR
-
-_default_edid = [
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3D, 0x17, 0x32, 0x12, 0x2A, 0x6A, 0xBF, 0x00,
- 0x05, 0x17, 0x01, 0x03, 0x80, 0x28, 0x1E, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xB2, 0x0C, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88,
- 0x36, 0x00, 0x28, 0x1E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x4D, 0x31, 0x20,
- 0x44, 0x56, 0x49, 0x20, 0x6D, 0x69, 0x78, 0x65, 0x72, 0x0A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34,
-]
-
-
-class EDID(Module, AutoCSR):
- def __init__(self, pads, default=_default_edid):
- self._hpd_notif = CSRStatus()
- self._hpd_en = CSRStorage()
- self.specials.mem = Memory(8, 128, init=default)
-
- ###
-
- # HPD
- if hasattr(pads, "hpd_notif"):
- self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status)
- else:
- self.comb += self._hpd_notif.status.eq(1)
- if hasattr(pads, "hpd_en"):
- self.comb += pads.hpd_en.eq(self._hpd_en.storage)
-
- # EDID
- scl_raw = Signal()
- sda_i = Signal()
- sda_raw = Signal()
- sda_drv = Signal()
- _sda_drv_reg = Signal()
- _sda_i_async = Signal()
- self.sync += _sda_drv_reg.eq(sda_drv)
- self.specials += [
- MultiReg(pads.scl, scl_raw),
- Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async),
- MultiReg(_sda_i_async, sda_raw)
- ]
-
- scl_i = Signal()
- samp_count = Signal(6)
- samp_carry = Signal()
- self.sync += [
- Cat(samp_count, samp_carry).eq(samp_count + 1),
- If(samp_carry,
- scl_i.eq(scl_raw),
- sda_i.eq(sda_raw)
- )
- ]
-
- scl_r = Signal()
- sda_r = Signal()
- scl_rising = Signal()
- sda_rising = Signal()
- sda_falling = Signal()
- self.sync += [
- scl_r.eq(scl_i),
- sda_r.eq(sda_i)
- ]
- self.comb += [
- scl_rising.eq(scl_i & ~scl_r),
- sda_rising.eq(sda_i & ~sda_r),
- sda_falling.eq(~sda_i & sda_r)
- ]
-
- start = Signal()
- self.comb += start.eq(scl_i & sda_falling)
-
- din = Signal(8)
- counter = Signal(max=9)
- self.sync += [
- If(start, counter.eq(0)),
- If(scl_rising,
- If(counter == 8,
- counter.eq(0)
- ).Else(
- counter.eq(counter + 1),
- din.eq(Cat(sda_i, din[:7]))
- )
- )
- ]
-
- is_read = Signal()
- update_is_read = Signal()
- self.sync += If(update_is_read, is_read.eq(din[0]))
-
- offset_counter = Signal(max=128)
- oc_load = Signal()
- oc_inc = Signal()
- self.sync += [
- If(oc_load,
- offset_counter.eq(din)
- ).Elif(oc_inc,
- offset_counter.eq(offset_counter + 1)
- )
- ]
- rdport = self.mem.get_port()
- self.specials += rdport
- self.comb += rdport.adr.eq(offset_counter)
- data_bit = Signal()
-
- zero_drv = Signal()
- data_drv = Signal()
- self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit))
-
- data_drv_en = Signal()
- data_drv_stop = Signal()
- self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0))
- self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True))
-
- fsm = FSM()
- self.submodules += fsm
-
- fsm.act("WAIT_START")
- fsm.act("RCV_ADDRESS",
- If(counter == 8,
- If(din[1:] == 0x50,
- update_is_read.eq(1),
- NextState("ACK_ADDRESS0")
- ).Else(
- NextState("WAIT_START")
- )
- )
- )
- fsm.act("ACK_ADDRESS0",
- If(~scl_i, NextState("ACK_ADDRESS1"))
- )
- fsm.act("ACK_ADDRESS1",
- zero_drv.eq(1),
- If(scl_i, NextState("ACK_ADDRESS2"))
- )
- fsm.act("ACK_ADDRESS2",
- zero_drv.eq(1),
- If(~scl_i,
- If(is_read,
- NextState("READ")
- ).Else(
- NextState("RCV_OFFSET")
- )
- )
- )
-
- fsm.act("RCV_OFFSET",
- If(counter == 8,
- oc_load.eq(1),
- NextState("ACK_OFFSET0")
- )
- )
- fsm.act("ACK_OFFSET0",
- If(~scl_i, NextState("ACK_OFFSET1"))
- )
- fsm.act("ACK_OFFSET1",
- zero_drv.eq(1),
- If(scl_i, NextState("ACK_OFFSET2"))
- )
- fsm.act("ACK_OFFSET2",
- zero_drv.eq(1),
- If(~scl_i, NextState("RCV_ADDRESS"))
- )
-
- fsm.act("READ",
- If(~scl_i,
- If(counter == 8,
- data_drv_stop.eq(1),
- NextState("ACK_READ")
- ).Else(
- data_drv_en.eq(1)
- )
- )
- )
- fsm.act("ACK_READ",
- If(scl_rising,
- oc_inc.eq(1),
- If(sda_i,
- NextState("WAIT_START")
- ).Else(
- NextState("READ")
- )
- )
- )
-
- for state in fsm.actions.keys():
- fsm.act(state, If(start, NextState("RCV_ADDRESS")))
- fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START")))
+++ /dev/null
-from migen import *
-from migen.bank.description import *
-from migen.genlib.misc import optree
-from migen.genlib.cdc import PulseSynchronizer
-
-from misoc.video.dvisampler.common import control_tokens
-
-
-class WER(Module, AutoCSR):
- def __init__(self, period_bits=24):
- self.data = Signal(10)
- self._update = CSR()
- self._value = CSRStatus(period_bits)
-
- ###
-
- # pipeline stage 1
- # we ignore the 10th (inversion) bit, as it is independent of the transition minimization
- data_r = Signal(9)
- self.sync.pix += data_r.eq(self.data[:9])
-
- # pipeline stage 2
- transitions = Signal(8)
- self.comb += [transitions[i].eq(data_r[i] ^ data_r[i+1]) for i in range(8)]
- transition_count = Signal(max=9)
- self.sync.pix += transition_count.eq(optree("+", [transitions[i] for i in range(8)]))
-
- is_control = Signal()
- self.sync.pix += is_control.eq(optree("|", [data_r == ct for ct in control_tokens]))
-
- # pipeline stage 3
- is_error = Signal()
- self.sync.pix += is_error.eq((transition_count > 4) & ~is_control)
-
- # counter
- period_counter = Signal(period_bits)
- period_done = Signal()
- self.sync.pix += Cat(period_counter, period_done).eq(period_counter + 1)
-
- wer_counter = Signal(period_bits)
- wer_counter_r = Signal(period_bits)
- wer_counter_r_updated = Signal()
- self.sync.pix += [
- wer_counter_r_updated.eq(period_done),
- If(period_done,
- wer_counter_r.eq(wer_counter),
- wer_counter.eq(0)
- ).Elif(is_error,
- wer_counter.eq(wer_counter + 1)
- )
- ]
-
- # sync to system clock domain
- wer_counter_sys = Signal(period_bits)
- self.submodules.ps_counter = PulseSynchronizer("pix", "sys")
- self.comb += self.ps_counter.i.eq(wer_counter_r_updated)
- self.sync += If(self.ps_counter.o, wer_counter_sys.eq(wer_counter_r))
-
- # register interface
- self.sync += If(self._update.re, self._value.status.eq(wer_counter_sys))
+++ /dev/null
-from migen import *
-from migen.flow.network import *
-from migen.flow import plumbing
-from migen.bank.description import AutoCSR
-from migen.actorlib import structuring, misc
-
-from misoc.mem.sdram.frontend import dma_lasmi
-from misoc.video.framebuffer.format import bpp, pixel_layout, FrameInitiator, VTG
-from misoc.video.framebuffer.phy import Driver
-
-
-class Framebuffer(Module, AutoCSR):
- def __init__(self, pads_vga, pads_dvi, lasmim):
- pack_factor = lasmim.dw//bpp
-
- g = DataFlowGraph()
-
- self.fi = FrameInitiator(lasmim.aw, pack_factor)
-
- intseq = misc.IntSequence(lasmim.aw, lasmim.aw)
- dma_out = AbstractActor(plumbing.Buffer)
- g.add_connection(self.fi, intseq, source_subr=self.fi.dma_subr())
- g.add_pipeline(intseq, AbstractActor(plumbing.Buffer), dma_lasmi.Reader(lasmim), dma_out)
-
- cast = structuring.Cast(lasmim.dw, pixel_layout(pack_factor), reverse_to=True)
- vtg = VTG(pack_factor)
- self.driver = Driver(pack_factor, pads_vga, pads_dvi)
-
- g.add_connection(self.fi, vtg, source_subr=self.fi.timing_subr, sink_ep="timing")
- g.add_connection(dma_out, cast)
- g.add_connection(cast, vtg, sink_ep="pixels")
- g.add_connection(vtg, self.driver)
- self.submodules += CompositeActor(g)
+++ /dev/null
-from migen import *
-from migen.genlib.misc import optree
-
-control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
-
-
-class Encoder(Module):
- def __init__(self):
- self.d = Signal(8)
- self.c = Signal(2)
- self.de = Signal()
-
- self.out = Signal(10)
-
- ###
-
- # stage 1 - count number of 1s in data
- d = Signal(8)
- n1d = Signal(max=9)
- self.sync += [
- n1d.eq(optree("+", [self.d[i] for i in range(8)])),
- d.eq(self.d)
- ]
-
- # stage 2 - add 9th bit
- q_m = Signal(9)
- q_m8_n = Signal()
- self.comb += q_m8_n.eq((n1d > 4) | ((n1d == 4) & ~d[0]))
- for i in range(8):
- if i:
- curval = curval ^ d[i] ^ q_m8_n
- else:
- curval = d[0]
- self.sync += q_m[i].eq(curval)
- self.sync += q_m[8].eq(~q_m8_n)
-
- # stage 3 - count number of 1s and 0s in q_m[:8]
- q_m_r = Signal(9)
- n0q_m = Signal(max=9)
- n1q_m = Signal(max=9)
- self.sync += [
- n0q_m.eq(optree("+", [~q_m[i] for i in range(8)])),
- n1q_m.eq(optree("+", [q_m[i] for i in range(8)])),
- q_m_r.eq(q_m)
- ]
-
- # stage 4 - final encoding
- cnt = Signal((6, True))
-
- s_c = self.c
- s_de = self.de
- for p in range(3):
- new_c = Signal(2)
- new_de = Signal()
- self.sync += new_c.eq(s_c), new_de.eq(s_de)
- s_c, s_de = new_c, new_de
-
- self.sync += If(s_de,
- If((cnt == 0) | (n1q_m == n0q_m),
- self.out[9].eq(~q_m_r[8]),
- self.out[8].eq(q_m_r[8]),
- If(q_m_r[8],
- self.out[:8].eq(q_m_r[:8]),
- cnt.eq(cnt + n1q_m - n0q_m)
- ).Else(
- self.out[:8].eq(~q_m_r[:8]),
- cnt.eq(cnt + n0q_m - n1q_m)
- )
- ).Else(
- If((~cnt[5] & (n1q_m > n0q_m)) | (cnt[5] & (n0q_m > n1q_m)),
- self.out[9].eq(1),
- self.out[8].eq(q_m_r[8]),
- self.out[:8].eq(~q_m_r[:8]),
- cnt.eq(cnt + Cat(0, q_m_r[8]) + n0q_m - n1q_m)
- ).Else(
- self.out[9].eq(0),
- self.out[8].eq(q_m_r[8]),
- self.out[:8].eq(q_m_r[:8]),
- cnt.eq(cnt - Cat(0, ~q_m_r[8]) + n1q_m - n0q_m)
- )
- )
- ).Else(
- self.out.eq(Array(control_tokens)[s_c]),
- cnt.eq(0)
- )
-
-
-class _EncoderSerializer(Module):
- def __init__(self, serdesstrobe, pad_p, pad_n):
- self.submodules.encoder = RenameClockDomains(Encoder(), "pix")
- self.d, self.c, self.de = self.encoder.d, self.encoder.c, self.encoder.de
-
- ###
-
- # 2X soft serialization
- ed_2x = Signal(5)
- self.sync.pix2x += ed_2x.eq(Mux(ClockSignal("pix"), self.encoder.out[:5], self.encoder.out[5:]))
-
- # 5X hard serialization
- cascade_di = Signal()
- cascade_do = Signal()
- cascade_ti = Signal()
- cascade_to = Signal()
- pad_se = Signal()
- self.specials += [
- Instance("OSERDES2",
- p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
- p_SERDES_MODE="MASTER", p_OUTPUT_MODE="DIFFERENTIAL",
-
- o_OQ=pad_se,
- i_OCE=1, i_IOCE=serdesstrobe, i_RST=0,
- i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"),
- i_D1=ed_2x[4], i_D2=0, i_D3=0, i_D4=0,
- i_T1=0, i_T2=0, i_T3=0, i_T4=0,
- i_TRAIN=0, i_TCE=1,
- i_SHIFTIN1=1, i_SHIFTIN2=1,
- i_SHIFTIN3=cascade_do, i_SHIFTIN4=cascade_to,
- o_SHIFTOUT1=cascade_di, o_SHIFTOUT2=cascade_ti),
- Instance("OSERDES2",
- p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
- p_SERDES_MODE="SLAVE", p_OUTPUT_MODE="DIFFERENTIAL",
-
- i_OCE=1, i_IOCE=serdesstrobe, i_RST=0,
- i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"),
- i_D1=ed_2x[0], i_D2=ed_2x[1], i_D3=ed_2x[2], i_D4=ed_2x[3],
- i_T1=0, i_T2=0, i_T3=0, i_T4=0,
- i_TRAIN=0, i_TCE=1,
- i_SHIFTIN1=cascade_di, i_SHIFTIN2=cascade_ti,
- i_SHIFTIN3=1, i_SHIFTIN4=1,
- o_SHIFTOUT3=cascade_do, o_SHIFTOUT4=cascade_to),
- Instance("OBUFDS", i_I=pad_se, o_O=pad_p, o_OB=pad_n)
- ]
-
-
-class PHY(Module):
- def __init__(self, serdesstrobe, pads):
- self.hsync = Signal()
- self.vsync = Signal()
- self.de = Signal()
- self.r = Signal(8)
- self.g = Signal(8)
- self.b = Signal(8)
-
- ###
-
- self.submodules.es0 = _EncoderSerializer(serdesstrobe, pads.data0_p, pads.data0_n)
- self.submodules.es1 = _EncoderSerializer(serdesstrobe, pads.data1_p, pads.data1_n)
- self.submodules.es2 = _EncoderSerializer(serdesstrobe, pads.data2_p, pads.data2_n)
- self.comb += [
- self.es0.d.eq(self.r),
- self.es1.d.eq(self.g),
- self.es2.d.eq(self.b),
- self.es0.c.eq(Cat(self.hsync, self.vsync)),
- self.es1.c.eq(0),
- self.es2.c.eq(0),
- self.es0.de.eq(self.de),
- self.es1.de.eq(self.de),
- self.es2.de.eq(self.de),
- ]
-
-
-class _EncoderTB(Module):
- def __init__(self, inputs):
- self.outs = []
- self._iter_inputs = iter(inputs)
- self._end_cycle = None
- self.submodules.dut = Encoder()
- self.comb += self.dut.de.eq(1)
-
- def do_simulation(self, selfp):
- if self._end_cycle is None:
- try:
- nv = next(self._iter_inputs)
- except StopIteration:
- self._end_cycle = selfp.simulator.cycle_counter + 4
- else:
- selfp.dut.d = nv
- if selfp.simulator.cycle_counter == self._end_cycle:
- raise StopSimulation
- if selfp.simulator.cycle_counter > 4:
- self.outs.append(selfp.dut.out)
-
-
-def _bit(i, n):
- return (i >> n) & 1
-
-
-def _decode_tmds(b):
- try:
- c = control_tokens.index(b)
- de = False
- except ValueError:
- c = 0
- de = True
- vsync = bool(c & 2)
- hsync = bool(c & 1)
-
- value = _bit(b, 0) ^ _bit(b, 9)
- for i in range(1, 8):
- value |= (_bit(b, i) ^ _bit(b, i-1) ^ (~_bit(b, 8) & 1)) << i
-
- return de, hsync, vsync, value
-
-if __name__ == "__main__":
- from migen.sim.generic import run_simulation
- from random import Random
-
- rng = Random(788)
- test_list = [rng.randrange(256) for i in range(500)]
- tb = _EncoderTB(test_list)
- run_simulation(tb)
-
- check = [_decode_tmds(out)[3] for out in tb.outs]
- assert(check == test_list)
-
- nb0 = 0
- nb1 = 0
- for out in tb.outs:
- for i in range(10):
- if _bit(out, i):
- nb1 += 1
- else:
- nb0 += 1
- print("0/1: {}/{} ({:.2f})".format(nb0, nb1, nb0/nb1))
+++ /dev/null
-from migen import *
-from migen.flow.actor import *
-from migen.bank.description import CSRStorage
-from migen.genlib.record import Record
-from migen.genlib.fsm import FSM, NextState
-from migen.actorlib import spi
-
-_hbits = 12
-_vbits = 12
-
-bpp = 32
-bpc = 10
-pixel_layout_s = [
- ("pad", bpp-3*bpc),
- ("r", bpc),
- ("g", bpc),
- ("b", bpc)
-]
-
-
-def pixel_layout(pack_factor):
- return [("p"+str(i), pixel_layout_s) for i in range(pack_factor)]
-
-bpc_phy = 8
-phy_layout_s = [
- ("r", bpc_phy),
- ("g", bpc_phy),
- ("b", bpc_phy)
-]
-
-
-def phy_layout(pack_factor):
- r = [("hsync", 1), ("vsync", 1), ("de", 1)]
- for i in range(pack_factor):
- r.append(("p"+str(i), phy_layout_s))
- return r
-
-
-class FrameInitiator(spi.SingleGenerator):
- def __init__(self, bus_aw, pack_factor, ndmas=1):
- h_alignment_bits = log2_int(pack_factor)
- hbits_dyn = _hbits - h_alignment_bits
- bus_alignment_bits = h_alignment_bits + log2_int(bpp//8)
- layout = [
- ("hres", hbits_dyn, 640, h_alignment_bits),
- ("hsync_start", hbits_dyn, 656, h_alignment_bits),
- ("hsync_end", hbits_dyn, 752, h_alignment_bits),
- ("hscan", hbits_dyn, 800, h_alignment_bits),
-
- ("vres", _vbits, 480),
- ("vsync_start", _vbits, 492),
- ("vsync_end", _vbits, 494),
- ("vscan", _vbits, 525),
-
- ("length", bus_aw + bus_alignment_bits, 640*480*bpp//8, bus_alignment_bits)
- ]
- layout += [("base"+str(i), bus_aw + bus_alignment_bits, 0, bus_alignment_bits)
- for i in range(ndmas)]
- spi.SingleGenerator.__init__(self, layout, spi.MODE_CONTINUOUS)
-
- timing_subr = ["hres", "hsync_start", "hsync_end", "hscan",
- "vres", "vsync_start", "vsync_end", "vscan"]
-
- def dma_subr(self, i=0):
- return ["length", "base"+str(i)]
-
-
-class VTG(Module):
- def __init__(self, pack_factor):
- hbits_dyn = _hbits - log2_int(pack_factor)
- timing_layout = [
- ("hres", hbits_dyn),
- ("hsync_start", hbits_dyn),
- ("hsync_end", hbits_dyn),
- ("hscan", hbits_dyn),
- ("vres", _vbits),
- ("vsync_start", _vbits),
- ("vsync_end", _vbits),
- ("vscan", _vbits)]
- self.timing = Sink(timing_layout)
- self.pixels = Sink(pixel_layout(pack_factor))
- self.phy = Source(phy_layout(pack_factor))
- self.busy = Signal()
-
- ###
-
- hactive = Signal()
- vactive = Signal()
- active = Signal()
-
- hcounter = Signal(hbits_dyn)
- vcounter = Signal(_vbits)
-
- skip = bpc - bpc_phy
- self.comb += [
- active.eq(hactive & vactive),
- If(active,
- [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:])
- for p in ["p"+str(i) for i in range(pack_factor)] for c in ["r", "g", "b"]],
- self.phy.de.eq(1)
- ),
- self.pixels.ack.eq(self.phy.ack & active)
- ]
-
- load_timing = Signal()
- tr = Record(timing_layout)
- self.sync += If(load_timing, tr.eq(self.timing.payload))
-
- generate_en = Signal()
- generate_frame_done = Signal()
- self.sync += [
- generate_frame_done.eq(0),
- If(generate_en,
- hcounter.eq(hcounter + 1),
-
- If(hcounter == 0, hactive.eq(1)),
- If(hcounter == tr.hres, hactive.eq(0)),
- If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)),
- If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)),
- If(hcounter == tr.hscan,
- hcounter.eq(0),
- If(vcounter == tr.vscan,
- vcounter.eq(0),
- generate_frame_done.eq(1)
- ).Else(
- vcounter.eq(vcounter + 1)
- )
- ),
-
- If(vcounter == 0, vactive.eq(1)),
- If(vcounter == tr.vres, vactive.eq(0)),
- If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)),
- If(vcounter == tr.vsync_end, self.phy.vsync.eq(0))
- )
- ]
-
- self.submodules.fsm = FSM()
- self.fsm.act("GET_TIMING",
- self.timing.ack.eq(1),
- load_timing.eq(1),
- If(self.timing.stb, NextState("GENERATE"))
- )
- self.fsm.act("GENERATE",
- self.busy.eq(1),
- If(~active | self.pixels.stb,
- self.phy.stb.eq(1),
- If(self.phy.ack, generate_en.eq(1))
- ),
- If(generate_frame_done, NextState("GET_TIMING"))
- )
+++ /dev/null
-from migen import *
-from migen.genlib.fifo import AsyncFIFO
-from migen.genlib.cdc import MultiReg
-from migen.bank.description import *
-from migen.flow.actor import *
-
-from misoc.video.framebuffer.format import bpc_phy, phy_layout
-from misoc.video.framebuffer import dvi
-
-
-class _FIFO(Module):
- def __init__(self, pack_factor):
- self.phy = Sink(phy_layout(pack_factor))
- self.busy = Signal()
-
- self.pix_hsync = Signal()
- self.pix_vsync = Signal()
- self.pix_de = Signal()
- self.pix_r = Signal(bpc_phy)
- self.pix_g = Signal(bpc_phy)
- self.pix_b = Signal(bpc_phy)
-
- ###
-
- fifo = RenameClockDomains(AsyncFIFO(phy_layout(pack_factor), 512),
- {"write": "sys", "read": "pix"})
- self.submodules += fifo
- self.comb += [
- self.phy.ack.eq(fifo.writable),
- fifo.we.eq(self.phy.stb),
- fifo.din.eq(self.phy.payload),
- self.busy.eq(0)
- ]
-
- unpack_counter = Signal(max=pack_factor)
- assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
- self.sync.pix += [
- unpack_counter.eq(unpack_counter + 1),
- self.pix_hsync.eq(fifo.dout.hsync),
- self.pix_vsync.eq(fifo.dout.vsync),
- self.pix_de.eq(fifo.dout.de)
- ]
- for i in range(pack_factor):
- pixel = getattr(fifo.dout, "p"+str(i))
- self.sync.pix += If(unpack_counter == i,
- self.pix_r.eq(pixel.r),
- self.pix_g.eq(pixel.g),
- self.pix_b.eq(pixel.b)
- )
- self.comb += fifo.re.eq(unpack_counter == (pack_factor - 1))
-
-
-# This assumes a 50MHz base clock
-class _Clocking(Module, AutoCSR):
- def __init__(self, pads_vga, pads_dvi):
- self._cmd_data = CSRStorage(10)
- self._send_cmd_data = CSR()
- self._send_go = CSR()
- self._status = CSRStatus(4)
-
- self.clock_domains.cd_pix = ClockDomain(reset_less=True)
- if pads_dvi is not None:
- self._pll_reset = CSRStorage()
- self._pll_adr = CSRStorage(5)
- self._pll_dat_r = CSRStatus(16)
- self._pll_dat_w = CSRStorage(16)
- self._pll_read = CSR()
- self._pll_write = CSR()
- self._pll_drdy = CSRStatus()
-
- self.clock_domains.cd_pix2x = ClockDomain(reset_less=True)
- self.clock_domains.cd_pix10x = ClockDomain(reset_less=True)
- self.serdesstrobe = Signal()
-
- ###
-
- # Generate 1x pixel clock
- clk_pix_unbuffered = Signal()
- pix_progdata = Signal()
- pix_progen = Signal()
- pix_progdone = Signal()
- pix_locked = Signal()
- self.specials += Instance("DCM_CLKGEN",
- p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=4, p_CLKFX_MD_MAX=1.0, p_CLKFX_MULTIPLY=2,
- p_CLKIN_PERIOD=20.0, p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE",
-
- i_CLKIN=ClockSignal("base50"), o_CLKFX=clk_pix_unbuffered,
- i_PROGCLK=ClockSignal(), i_PROGDATA=pix_progdata, i_PROGEN=pix_progen,
- o_PROGDONE=pix_progdone, o_LOCKED=pix_locked,
- i_FREEZEDCM=0, i_RST=ResetSignal())
-
- remaining_bits = Signal(max=11)
- transmitting = Signal()
- self.comb += transmitting.eq(remaining_bits != 0)
- sr = Signal(10)
- self.sync += [
- If(self._send_cmd_data.re,
- remaining_bits.eq(10),
- sr.eq(self._cmd_data.storage)
- ).Elif(transmitting,
- remaining_bits.eq(remaining_bits - 1),
- sr.eq(sr[1:])
- )
- ]
- self.comb += [
- pix_progdata.eq(transmitting & sr[0]),
- pix_progen.eq(transmitting | self._send_go.re)
- ]
-
- # enforce gap between commands
- busy_counter = Signal(max=14)
- busy = Signal()
- self.comb += busy.eq(busy_counter != 0)
- self.sync += If(self._send_cmd_data.re,
- busy_counter.eq(13)
- ).Elif(busy,
- busy_counter.eq(busy_counter - 1)
- )
-
- mult_locked = Signal()
- self.comb += self._status.status.eq(Cat(busy, pix_progdone, pix_locked, mult_locked))
-
- # Clock multiplication and buffering
- if pads_dvi is None:
- # Just buffer 1x pixel clock
- self.specials += Instance("BUFG", i_I=clk_pix_unbuffered, o_O=self.cd_pix.clk)
- self.comb += mult_locked.eq(pix_locked)
- else:
- # Route unbuffered 1x pixel clock to PLL
- # Generate 1x, 2x and 10x IO pixel clocks
- clkfbout = Signal()
- pll_locked = Signal()
- pll_clk0 = Signal()
- pll_clk1 = Signal()
- pll_clk2 = Signal()
- locked_async = Signal()
- pll_drdy = Signal()
- self.sync += If(self._pll_read.re | self._pll_write.re,
- self._pll_drdy.status.eq(0)
- ).Elif(pll_drdy,
- self._pll_drdy.status.eq(1)
- )
- self.specials += [
- Instance("PLL_ADV",
- p_CLKFBOUT_MULT=10,
- p_CLKOUT0_DIVIDE=1, # pix10x
- p_CLKOUT1_DIVIDE=5, # pix2x
- p_CLKOUT2_DIVIDE=10, # pix
- p_COMPENSATION="INTERNAL",
-
- i_CLKINSEL=1,
- i_CLKIN1=clk_pix_unbuffered,
- o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
- o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
- o_LOCKED=pll_locked,
- i_RST=~pix_locked | self._pll_reset.storage,
-
- i_DADDR=self._pll_adr.storage,
- o_DO=self._pll_dat_r.status,
- i_DI=self._pll_dat_w.storage,
- i_DEN=self._pll_read.re | self._pll_write.re,
- i_DWE=self._pll_write.re,
- o_DRDY=pll_drdy,
- i_DCLK=ClockSignal()),
- Instance("BUFPLL", p_DIVIDE=5,
- i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked,
- o_IOCLK=self.cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
- Instance("BUFG", i_I=pll_clk1, o_O=self.cd_pix2x.clk),
- Instance("BUFG", name="dviout_pix_bufg", i_I=pll_clk2, o_O=self.cd_pix.clk),
- MultiReg(locked_async, mult_locked, "sys")
- ]
-
- # Drive VGA/DVI clock pads
- if pads_vga is not None:
- self.specials += Instance("ODDR2",
- p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
- o_Q=pads_vga.clk,
- i_C0=ClockSignal("pix"),
- i_C1=~ClockSignal("pix"),
- i_CE=1, i_D0=1, i_D1=0,
- i_R=0, i_S=0)
- if pads_dvi is not None:
- dvi_clk_se = Signal()
- self.specials += Instance("ODDR2",
- p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
- o_Q=dvi_clk_se,
- i_C0=ClockSignal("pix"),
- i_C1=~ClockSignal("pix"),
- i_CE=1, i_D0=1, i_D1=0,
- i_R=0, i_S=0)
- self.specials += Instance("OBUFDS", i_I=dvi_clk_se,
- o_O=pads_dvi.clk_p, o_OB=pads_dvi.clk_n)
-
-
-class Driver(Module, AutoCSR):
- def __init__(self, pack_factor, pads_vga, pads_dvi):
- fifo = _FIFO(pack_factor)
- self.submodules += fifo
- self.phy = fifo.phy
- self.busy = fifo.busy
-
- self.submodules.clocking = _Clocking(pads_vga, pads_dvi)
-
- if pads_vga is not None:
- self.comb += [
- pads_vga.hsync_n.eq(~fifo.pix_hsync),
- pads_vga.vsync_n.eq(~fifo.pix_vsync),
- pads_vga.r.eq(fifo.pix_r),
- pads_vga.g.eq(fifo.pix_g),
- pads_vga.b.eq(fifo.pix_b),
- pads_vga.psave_n.eq(1)
- ]
- if pads_dvi is not None:
- self.submodules.dvi_phy = dvi.PHY(self.clocking.serdesstrobe, pads_dvi)
- self.comb += [
- self.dvi_phy.hsync.eq(fifo.pix_hsync),
- self.dvi_phy.vsync.eq(fifo.pix_vsync),
- self.dvi_phy.de.eq(fifo.pix_de),
- self.dvi_phy.r.eq(fifo.pix_r),
- self.dvi_phy.g.eq(fifo.pix_g),
- self.dvi_phy.b.eq(fifo.pix_b)
- ]
from setuptools import find_packages
-required_version = (3, 3)
-if sys.version_info < required_version:
- raise SystemExit("MiSoC requires python {0} or greater".format(
- ".".join(map(str, required_version))))
+if sys.version_info[:3] < (3, 3):
+ raise SystemExit("You need Python 3.3+")
+
setup(
name="misoc",