Skip to content

Litex and FPGA

Litex

fjullien migen_litex_tutorials <-- Best Litex tutorial

Local migen_litex_tutorials

officail litx wiki.

Litex MIPI CSI

ICEStorm Install icestorm_install.md

getting-started-with-litex


LiteLib

💾LiteLIB

LiteLib provides a collection of small, reusable hardware building blocks for Migen-based FPGA designs. These cores fill gaps not covered by LiteX's built-in core library.

Originally ported from the Amaranth-based amlib utility library, all cores are pure Migen with no LiteX dependency — they can be used standalone in any Migen project or integrated into a LiteX SoC.


Litex and Efinix 2026-08

  • Use Ubuntu 22.04 Python > 3.9
  • No venv needed
  • Install Litex along side efinix Tools
  • Pay attention to which python3 path
  • Only set LITEX_ENV_EFINITY="~/efinity-yyyy-d-linux-x64/efinity/yyyy.mm"

Litex Radiant Synth Tool Change

Add "--synth-mode=lse" after "--build"


Litex CSR is the Key to Connect to the Bus and the World


Litex without CPU

class BaseSoC(SoCMini):
    def __init__(self, platform, **kwargs):
        sys_clk_freq = int(100e6)

        # SoCMini (No CPU, we are controlling the SoC over UART)
        SoCMini.__init__(self, platform, sys_clk_freq, 
                         csr_data_width=32,
                         ident="Hello World! \r\n", 
                         ident_version=True)

        # No CPU, use Serial to control Wishbone bus
        self.add_uartbone(name="uart_debug", baudrate=115200)
        #self.add_jtagbone()
        # FPGA identification
        self.submodules.dna = dna.DNA()
        self.add_csr("dna")

Litex Bus

        # Wishbone Master
        serwb_slave_core = SERWBCore(self.serwb_slave_phy, self.clk_freq, mode="master")
        self.submodules += serwb_slave_core

        # Wishbone SRAM
        self.serwb_sram = wishbone.SRAM(8192)
        # self.comb += serwb_slave_core.bus.connect(self.serwb_sram.bus)

        # You cannot do it.
        self.submodules.wbreg = wbreg = WBSlave_Reg()
        # self.comb += serwb_slave_core.bus.connect(wbreg.bus)

        self.slave_bus = SoCBusHandler(
            name             = "SoCSlaveBusHandler",
            standard         = "wishbone",
            data_width       = 32,
            address_width    = 32,
        )
        self.slave_bus.add_master("s_master", serwb_slave_core.bus)
        self.slave_bus.add_slave("ssram", self.serwb_sram.bus, region=SoCRegion(origin=0x3000_0000, size=0x0000_2000))
        self.slave_bus.add_slave("sreg", wbreg.bus, region=SoCRegion(origin=0x3000_3000, size=0x0000_1000))

Litex Instance External Verilog

din    = Signal(32)
dout   = Signal(32)
dinout = Signal(32)
self.specials += Instance("custom_core",
   p_DATA_WIDTH = 32,
   i_din     = din,
   o_dout    = dout,
   io_dinout = dinout
)

#################################################################

# Create a Dict for the Parameters/IOs.
params_ios = dict()

# Add the Parameters.
params_ios.update(
   p_DATA_WIDTH = 32
)
# Add the IOs.
params_ios.update(
   i_din     = din,
   o_dout    = dout,
   io_dinout = dinout
)
# Do the Instance:
self.specials += Instance("custom_core", **self.params_ios)

#################################################################

for i in range(fifo_ports):
    litedram_params.update(**{
        # FIFO In.
        f"i_user_fifo_{i}_in_valid": axis_in[i].valid,
        f"o_user_fifo_{i}_in_ready": axis_in[i].ready,
        f"i_user_fifo_{i}_in_data" : axis_in[i].data,

        # FIFO Out.
        f"o_user_fifo_{i}_out_valid": axis_out[i].valid,
        f"i_user_fifo_{i}_out_ready": axis_out[i].ready,
        f"o_user_fifo_{i}_out_data" : axis_out[i].data,
})

#################################################################

platform.add_sources("./", #Search path location
  "core0.v",
  "core1.vhd",
  "core2.sv"
)

Reuse a (System)Verilog


Litex use Radiant IP to wrap into Module

class Counter(LiteXModule):
   def __init__(self, platform):
       self.co = Signal()

       platform.add_sources("./myCounter/rtl",
           "myCounter.v",
       )
       platform.add_sources("./myCounter/constraints",
           "myCounter.ldc",
       )
       clk_en_i = Signal()
       q_o = Signal(24)

       self.comb += [
          clk_en_i.eq(1),
          self.co.eq(q_o[23])
       ]
       self.specials += Instance("myCounter",
           i_clk_i    = ClockSignal("sys"),
           i_clk_en_i  = clk_en_i,
           i_aclr_i    = ResetSignal("sys"),
           o_q_o    = q_o
       )

Litex SPI Master with FIFO

#
# This file is part of LiteSPI
#
# Copyright (c) 2020 Antmicro <www.antmicro.com>
# SPDX-License-Identifier: BSD-2-Clause

from migen import *

from litex.gen import *

from litex.soc.interconnect import stream
from litex.soc.interconnect.csr import *
from litex.soc.interconnect.csr_eventmanager import *

from litespi.common import *


class LiteSPIMaster(LiteXModule):
    """Generic LiteSPI Master

    The ``LiteSPIMaster`` class provides a generic SPI master that can be controlled using CSRs.

    It supports multiple access modes with help of ``width`` and ``mask`` registers which can be used to configure the PHY into any supported SDR mode (single/dual/quad/octal).

    Parameters
    ----------
    fifo_depth : int
        Depth of the internal TX/RX FIFO.

    cs_width : int
        Number of CS lines to support.

    Attributes
    ----------
    source : Endpoint(spi_phy2core_layout), out
        Data stream.

    sink : Endpoint(spi_core2phy_layout), in
        Control stream.

    cs : Signal(), out
        Slave CS signal.

    """
    def __init__(self, cs_width=1, tx_fifo_depth=1, rx_fifo_depth=1, with_irq=False):
        self.sink   = stream.Endpoint(spi_phy2core_layout)
        self.source = stream.Endpoint(spi_core2phy_layout)
        self.cs     = Signal(cs_width)
        assert self.sink.data.nbits == self.source.data.nbits

        self._cs = CSRStorage(cs_width)
        self._phyconfig = CSRStorage(fields=[
            CSRField("len",   size=len(self.source.len), offset=0,  description="SPI Xfer length (in bits)."),
            CSRField("width", size=4, offset=8,  description="SPI Xfer width (1/2/4/8)."),
            CSRField("mask",  size=8, offset=16, description="SPI DQ output enable mask (set bits to ``1`` to enable output drivers on DQ lines)."),
        ], description="SPI PHY settings.")
        self._rxtx = CSR(self.source.data.nbits)
        self._status = CSRStatus(fields=[
            CSRField("tx_ready", size=1, offset=0, description="TX FIFO is not full."),
            CSRField("rx_ready", size=1, offset=1, description="RX FIFO is not empty."),
        ])

        # Clock Divider.
        self._clk_divisor = CSRStorage(len(self.source.clk_div))

        # # #

        # FIFOs.
        self.tx_fifo = tx_fifo = stream.SyncFIFO(spi_core2phy_layout, depth=tx_fifo_depth)
        self.rx_fifo = rx_fifo = stream.SyncFIFO(spi_phy2core_layout, depth=rx_fifo_depth)
        self.comb += self.sink.connect(rx_fifo.sink)
        self.comb += tx_fifo.source.connect(self.source)

        # SPI CS.
        self.comb += self.cs.eq(self._cs.storage)

        # SPI TX (MOSI).
        self.comb += [
            tx_fifo.sink.valid.eq(self._rxtx.wr_stb),
            self._status.fields.tx_ready.eq(tx_fifo.sink.ready),
            tx_fifo.sink.data.eq(self._rxtx.wr_data),
            tx_fifo.sink.len.eq(self._phyconfig.fields.len),
            tx_fifo.sink.width.eq(self._phyconfig.fields.width),
            tx_fifo.sink.mask.eq(self._phyconfig.fields.mask),
            tx_fifo.sink.clk_div.eq(self._clk_divisor.storage),
        ]

        # SPI RX (MISO).
        self.comb += [
            rx_fifo.source.ready.eq(self._rxtx.rd_stb),
            self._status.fields.rx_ready.eq(rx_fifo.source.valid),
            self._rxtx.rd_data.eq(rx_fifo.source.data),
        ]

        if with_irq:
            self.ev            = EventManager()
            self.ev.rx_ready   = EventSourceProcess(edge="rising")
            self.ev.finalize()

            self.comb += [
                self.ev.rx_ready.trigger.eq(rx_fifo.source.valid),
            ]

Litex Setting for Radiant Setting

In BaseSOC

       platform.add_platform_command(
           "ldc_set_sysconfig {{JTAG_PORT=ENABLE MCCLK_FREQ=14.1 DONE_PORT=ENABLE INITN_PORT=ENABLE PROGRAMN_PORT=ENABLE DONE_OD=ON WAKE_UP=ENABLE_DONE_SYNC MASTER_SPI_PORT=SERIAL}}"
       )
       platform.add_platform_command(
           "ldc_set_sysconfig {{MASTER_SPI_PORT=SERIAL BOOTMODE=SINGLE CONFIGIO_VOLTAGE_BANK0=1.8 CONFIGIO_VOLTAGE_BANK1=1.8 CONFIG_IOSLEW=FAST}}"
       )

In Build main()

        parser.set_defaults(synth_mode="lse")

Creating LiteX wrappers

📑Creating LiteX wrappers


Migen Simulation

Counter

from migen import *

class DPLL(Module):
    def __init__(self):
        self.count = Signal(4)

        self.sync += self.count.eq(self.count + 1)

def dpll_test(dut):
    for i in range(20):
         print((yield dut.count))
         yield

if __name__ == "__main__":
    dut = DPLL()
    run_simulation(dut, dpll_test(dut), vcd_name="dpll.vcd")

Migen Selection of Signal from Signal as Index

        shiftout = Array({} for i in range(REG_Number))

        for i in range(16):
            shiftout[0][i] = [self.spi_miso1.eq(Regsiters[0][i] & ~self.spi_cs)]
            shiftout[1][i] = [self.spi_miso2.eq(Regsiters[1][i] & ~self.spi_cs)]

        for i in range(REG_Number):
            self.comb += [
                Case(shift_count, shiftout[i])
            ]

Migen Case

        self.comb += Case(word_cound,{
            0: self.uart_tx.eq(start_b0),
            1: self.uart_tx.eq(start_b1),
            2: self.uart_tx.eq(timestamp_b0),
            3: self.uart_tx.eq(timestamp_b1),
            4: self.uart_tx.eq(timestamp_b2),
            5: self.uart_tx.eq(timestamp_b3),
            "default": self.uart_tx.eq(0),
        })

Migen Module

        encoder = Encoder8b10b()
        decoder = Decoder8b10b()

        self.submodules += [
            encoder, decoder
        ]

Migen Reset FSM

        fsm   = FSM(reset_state="WAIT")
        fsm   = ClockDomainsRenamer("icap")(fsm)
        fsm   = ResetInserter()(fsm)
        self.submodules += fsm
        self.comb += fsm.reset.eq(~(self.write | self.read))

IceStorm toolset for ICE40 FPGA

# Project setup
PROJ      = blinky
BUILD     = ./build
DEVICE    = 8k
FOOTPRINT = ct256

# Files
FILES = top.v

.PHONY: all clean burn timing

all $(BUILD)/$(PROJ).asc $(BUILD)/$(PROJ).bin:
    # if build folder doesn't exist, create it
    mkdir -p $(BUILD)
    # synthesize using Yosys
    yosys -p "synth_ice40 -top top -blif $(BUILD)/$(PROJ).blif -json $(BUILD)/$(PROJ).json" $(FILES)
    # Place and route using arachne
    #arachne-pnr -d $(DEVICE) -P $(FOOTPRINT) -o $(BUILD)/$(PROJ).asc -p pinmap.pcf $(BUILD)/$(PROJ).blif
    nextpnr-ice40 --hx$(DEVICE) --json build/$(PROJ).json --pcf pinmap.pcf --asc build/$(PROJ).asc
    # Convert to bitstream using IcePack
    icepack $(BUILD)/$(PROJ).asc $(BUILD)/$(PROJ).bin

burn: $(BUILD)/$(PROJ).bin
    iceprog $(BUILD)/$(PROJ).bin

timing: $(BUILD)/$(PROJ).asc
    icetime -tmd hx$(DEVICE) $(BUILD)/$(PROJ).asc

clean:
    rm build/*

Lattice Radiant and Propel

Lattice Propel and Radiant Install IP or Module

ip_catalog_install -vlnv latticesemi.com:ip:debayer:1.4.1

Chisel FPGA開発日記

https://msyksphinz.hatenablog.com/

https://www.hatena.ne.jp/

https://hatenablog.com/

Agile Hardware Design Video 2024

Chip Alliance

Chip Alliance


Amaranth

Amaranth HDL Document


Verilog

https://verilogguide.readthedocs.io/en/latest/

https://www.chipverify.com/

Verilog Tutorial


The Art of FPGA Design - element14 Community

The Art of FPGA Design - element14 Community

Digital Signal Processing, from Algorithm to FPGA Bitstream - element14 Community

Digital Signal Processing, from Algorithm to FPGA Bitstream


Xilinx Petalinux

使用Buildroot编译AMD/Xilinx Zynq ZC702 单板 Linux (内核和文件系统)

🌐使用Buildroot编译AMD/Xilinx Zynq ZC702 单板 Linux (内核和文件系统)


ZCU104_MPSoC Development - Petalinux 2024.2 Basic Tutorial

🌐ZCU104_MPSoC Development - Petalinux 2024.2 Basic Tutorial


Xillinux

🌐Xillinux: A Linux distribution for Z-Turn Lite, Zedboard, ZyBo and MicroZed

The Xillinux distribution is a software + FPGA code kit for running a full-blown graphical desktop on the Z-Turn Lite, Zedboard and (non-Z7) ZyBo, attaching a monitor, keyboard and mouse to the board itself. Xillinux also supports MicroZed without the graphics.


UltraZed-EG PCIe Carrier Card 開發紀錄

🌐UltraZed-EG PCIe Carrier Card 開發紀錄 使用 PetaLinux 建立系統


Petalinux Demo

🎬Xilinx Zynq & PetaLinux Project Demo

🎬PetaLinux SPI Device Control LCD Panel

🎬Creating Multi-Boot Bitstream In Xilinx FPGA

🎬Xilinx HLS Project Demo - SHA256 Calculation


Perfecting PetaLinux Workshop

💾Perfecting PetaLinux Workshop

🎬Perfecting PetaLinux Workshop

📚PetaLinux Tools Documentation: Reference Guide (UG1144)


Vivado Vitis Petalinux 2024 on Ubuntu 2024

🌐Vivado Vitis Petalinux 2024.2

🌐Hardware acceleration in FPGA with Vivado and Vitis

🌐Vivado 2024 on Ubuntu 2024


Zynq PetaLinux and Vitis

🌐Zynq PetaLinux 2024-1

🌐Fixed Platform Design on Zynq-7000 in Vitis 2024.1