Repository navigation
Create A Complex SoC
DRAM (LiteDRAM), Ethernet (LiteEth), an SD card (LiteSDCard), a SPI flash (LiteSPI), SATA
(LiteSATA), PCIe (LitePCIe), video: each is a PHY matching the board's chip plus one add_*
call, and brings its BIOS commands, its boot method and its Linux driver along. We walk
through the Digilent Arty A7 target, the one the Linux SoC is built on; the other LiteX-Boards
targets do the same for their boards. Count an hour after the minimal SoC.
The full version is litex_boards/targets/digilent_arty.py; this is its skeleton with the
ecosystem cores:
from litex.soc.cores.clock import *
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litedram.modules import MT41K128M16
from litedram.phy import s7ddrphy
from liteeth.phy.mii import LiteEthPHYMII
class BaseSoC(SoCCore):
def __init__(self, sys_clk_freq=100e6, with_ethernet=False, with_etherbone=False, eth_ip="192.168.1.50",
with_spi_flash=False, **kwargs):
platform = digilent_arty.Platform()
# CRG: sys, sys4x, sys4x_dqs and idelay clocks for the DDR3, 25 MHz for the Ethernet PHY.
self.crg = _CRG(platform, sys_clk_freq, with_dram=(kwargs.get("integrated_main_ram_size", 0) == 0))
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Arty A7", **kwargs)
# DDR3 SDRAM: LiteDRAM ----------------------------------------------------------------------
if not self.integrated_main_ram_size:
self.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"),
memtype = "DDR3",
nphases = 4,
sys_clk_freq = sys_clk_freq)
self.add_sdram("sdram",
phy = self.ddrphy,
module = MT41K128M16(sys_clk_freq, "1:4"),
l2_cache_size = kwargs.get("l2_size", 8192))
# Ethernet / Etherbone: LiteEth -------------------------------------------------------------
if with_ethernet or with_etherbone:
self.ethphy = LiteEthPHYMII(
clock_pads = self.platform.request("eth_clocks"),
pads = self.platform.request("eth"))
if with_etherbone:
self.add_etherbone(phy=self.ethphy, ip_address=eth_ip, with_ethmac=with_ethernet)
elif with_ethernet:
self.add_ethernet(phy=self.ethphy, local_ip=eth_ip)
# SPI Flash: LiteSPI ----------------------------------------------------------------------
if with_spi_flash:
from litespi.modules import S25FL128L
from litespi.opcodes import SpiNorFlashOpCodes as Codes
self.add_spi_flash(mode="4x", module=S25FL128L(Codes.READ_1_1_4), rate="1:2", with_master=True)
# main(): ... soc.add_sdcard() with --with-sdcard, soc.add_spi_sdcard() with --with-spi-sdcard ...python3 -m litex_boards.targets.digilent_arty --cpu-type=vexriscv --cpu-variant=linux \
--with-ethernet --with-sdcard --with-spi-flash --with-xadc --build --loadWhat each core adds, from the log of that build (--build --no-compile shows it in seconds):
Bus Regions: (8)
rom : Origin: 0x00000000, Size: 0x00020000, Mode: RX, Cached: True, Linker: False
spiflash : Origin: 0x01000000, Size: 0x01000000, Mode: RX, Cached: True, Linker: False
sram : Origin: 0x10000000, Size: 0x00002000, Mode: RWX, Cached: True, Linker: False
main_ram : Origin: 0x40000000, Size: 0x10000000, Mode: RWX, Cached: True, Linker: False
ethmac : Origin: 0x80000000, Size: 0x00002000, Mode: RW, Cached: False, Linker: True
ethmac_rx : Origin: 0x80000000, Size: 0x00001000, Mode: R, Cached: False, Linker: False
ethmac_tx : Origin: 0x80001000, Size: 0x00001000, Mode: RW, Cached: False, Linker: False
csr : Origin: 0xf0000000, Size: 0x00010000, Mode: RW, Cached: False, Linker: False
Bus Masters: (4)
- cpu_bus0 : rw
- cpu_bus1 : rw
- sdcard_block2mem : w
- sdcard_mem2block : r
CSR Locations: (12)
- ctrl, ddrphy, ethmac, ethphy, identifier_mem, leds, sdcard, sdram, spiflash, timer0, uart, xadc
IRQ Locations: (4)
- uart : 0, timer0 : 1, ethmac : 2, sdcard : 3
-
Gateware: the PHY for the FPGA family and memory type (
s7ddrphy.A7DDRPHY/K7DDRPHYDDR3 on 7-Series,usddrphy.USDDRPHY/USPDDRPHYDDR3/DDR4 on UltraScale(+),ecp5ddrphy.ECP5DDRPHYon ECP5,gw2ddrphy.GW2DDRPHYon Gowin,gensdrphy.GENSDRPHYfor SDR SDRAM anywhere, thes6ddrphyon Spartan-6, the LPDDR4 PHYs...), the module of the chip (litedram.modules, with its timings; a new chip is a few lines from its datasheet), andadd_sdram(): the controller, themain_ramregion, the L2 cache in front of the main bus (--l2-size), direct crossbar ports for the CPUs that have memory buses (VexRiscv-SMP, NaxRiscv, VexiiRiscv, Rocket),sdram_phy.hwith the calibration parameters. The CRG must provide the clocks the PHY declares (sys4x,sys4x_dqs,idelayon 7-Series). -
BIOS: calibrates the DRAM at boot (
Initializing SDRAM, read/write leveling on DDR3/4), runs the memtest and the memspeed, and offerssdram_init,sdram_cal,sdram_test,sdram_bist,sdram_spd... Linux and the applications get themain_ramregion; a DMA (WishboneDMAReader/Writer, the LiteDRAM native ports) reaches it without the CPU. -
Options:
--integrated-main-ram-sizereplaces the DRAM by block RAM (no PHY), useful on small boards and in simulation;with_bist=Trueadds a hardware generator/checker.
-
Gateware: the PHY for the interface (
LiteEthPHYMII,LiteEthPHYRMII,LiteEthPHYGMII,LiteEthPHYRGMIIper family inliteeth.phy,LiteEthPHY1000BaseX/SGMII on transceivers,LiteEthPHYXGMII...) andadd_ethernet(phy, local_ip, remote_ip, nrxslots, ntxslots, with_timestamp, with_dhcp): the MAC with its RX/TX slots (ethmacregion, uncached, 2 + 2 slots of 2 KiB), the interrupt, theLOCALIP/REMOTEIP/MACADDRconstants.add_etherbone(phy, ip_address, mac_address, udp_port)instead (or in addition,with_ethmac=Trueshares the PHY) gives the host a bridge with the hardware UDP/IP stack. -
BIOS:
netboot(TFTP,boot.json/boot.bin),ping,eth_dhcp,eth_local_ip,mdio_*; Linux gets thelitex_liteethdriver through the device tree. -
Options:
--eth-ip,--remote-ip,--eth-dhcp/--eth-dynamic-ip,--with-ethernetand--with-etherboneare mutually exclusive on the targets unless the target shares the PHY.
-
add_sdcard(): the 4-bit SD/eMMC controller with its DMAs (sdcard_block2mem,sdcard_mem2blockbus masters), BIST, interrupt;add_spi_sdcard(): the bit-banged SPI mode for boards without the data pins (slow, no DMA). BIOS:sdcardboot(FAT,boot.json),sdcard_init,sdcard_read/sdcard_write; Linux:litex_mmc. -
add_sata(phy=LiteSATAPHY(...), mode="read+write", with_bist=True): the SATA controller with itssector2mem/mem2sectorDMAs, on the transceivers (7-Series GTP/GTX, UltraScale(+), ECP5). BIOS:sataboot,sata_init,sata_read/sata_write,sata_rwtest.
-
add_spi_flash(mode="4x", module=S25FL128L(Codes.READ_1_1_4), rate="1:2", with_master=True): the memory-mapped flash (spiflashregion, execute in place, the BIOS can even live there with--cpu-reset-addressat a flash offset) and the master for erase/program (with_master), theSPIFLASH_*constants andFLASH_BOOT_ADDRESSfor theflashboot. The module and the read opcode come from the datasheet (litespi.moduleshas many). -
BIOS:
flashboot,flash_write,flash_erase_range,flash_from_sdcard.
-
add_video_framebuffer(phy, timings="800x600@60Hz", format="rgb888"): a framebuffer in main RAM read by DMA, the timings generator, and a PHY for the output (VideoVGAPHY,VideoDVIPHY,VideoHDMIPHY,VideoS7HDMIPHY,VideoGowinHDMIPHY...);add_video_terminalshows the console on the screen,add_video_colorbarsa test pattern; the boards with HDMI have--with-video-framebuffer/--with-video-terminal. Linux gets asimple-framebuffernode (Cores).
add_pcie(phy=S7PCIEPHY(...), ndmas=1): the endpoint, the host bridge to the
whole SoC bus, the DMAs and MSI, the Linux driver and user tools: Create a PCIe SoC.
--with-xadc/--with-dna (Xilinx), --with-buttons, --with-switches, --with-pmod-gpio,
--with-can, --with-i2c, --with-spi, USB (--uart-name=usb_acm), the watchdog, the
--pmod pmodd=sdcard extensions: the in-tree cores.
With a DRAM, Ethernet or an SD card and a linux-capable CPU, the SoC runs Linux:
litex_json2dts_linux build/<board>/csr.json > soc.dts generates the device tree from the
same description (every core the kernel has a driver for gets its node), and Linux-on-LiteX-VexRiscv packages
the kernel, OpenSBI, Buildroot and the boot images for the LiteX-Boards targets. Zephyr,
FreeRTOS and MicroPython use the same headers (OSes ecosystem).
-
--build --no-compile: the map, the CSRs and the interrupts in seconds;csr.csvfor the host tools. - The BIOS tests every core at boot (DRAM memtest) or on request (
sdcard_init,ping,flash_*);litex_cli --regs --filter sdramreads the calibration registers;--with-uartbonegives the host the bus while the CPU runs. -
LiteScope on the signals of a core that misbehaves, in
simulation first:
litex_sim --with-sdram --with-ethernet --with-sdcard --with-spi-flashhas models for all of them.
- Run Linux on your SoC: boot Linux on this SoC.
-
Cores ecosystem: the repositories behind each
add_*. - Create a PCIe SoC: the PCIe core in detail.
- Add a new board: the platform these cores need pins from.
Have a question or want to get in touch? Join us on Discord or on IRC: #litex at irc.libera.chat. This wiki is generated from doc/wiki in the LiteX repository: edit it with a pull request.
- Start here
- Build your SoC
- Run software on it
- How LiteX works
- Reference
- Projects and community
- For AI agents