├── .gitignore ├── init ├── .vscode └── settings.json ├── install.sh ├── LICENSE ├── .gitmodules ├── README.md ├── .github └── workflows │ └── ci.yml ├── soc_zephyr.py └── make.py /.gitignore: -------------------------------------------------------------------------------- 1 | tools 2 | build 3 | prog 4 | __pycache__ 5 | -------------------------------------------------------------------------------- /init: -------------------------------------------------------------------------------- 1 | export PATH="${PWD}/third_party/litex/litex/tools:$PATH" 2 | export PATH="${PWD}/tools/conda/bin:$PATH" 3 | 4 | directories=(litedram liteeth litei2c liteiclink litepcie litespi litesata litescope litevideo litex litex-boards litex-renode migen nmigen pythondata-cpu-vexriscv pythondata-software-compiler_rt pythondata-software-picolibc) 5 | 6 | for directory in "${directories[@]}"; 7 | do 8 | export PYTHONPATH="$PYTHONPATH:${PWD}/third_party/$directory" 9 | done 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.extraPaths": [ 3 | "./third_party/migen", 4 | "./third_party/litex", 5 | "./third_party/litex-boards", 6 | "./third_party/litei2c", 7 | "./third_party/litespi", 8 | "./third_party/litedram", 9 | "./third_party/liteeth", 10 | "./third_party/litepcie", 11 | "./third_party/litevideo", 12 | "./third_party/litescope" 13 | ] 14 | } -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | pip3 install --user requests packaging 5 | 6 | TOOLS_DIR='tools' 7 | CONDA_DIR="$TOOLS_DIR/conda" 8 | if [[ -d "$CONDA_DIR" ]] 9 | then 10 | exit 1 11 | fi 12 | 13 | mkdir -p "$CONDA_DIR" 14 | 15 | wget --no-verbose --continue https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh 16 | bash Miniconda3-latest-Linux-x86_64.sh -p "$CONDA_DIR" -b -f || exit 2 17 | rm ./Miniconda3-latest-Linux-x86_64.sh 18 | 19 | export PATH="$CONDA_DIR/bin:$PATH" 20 | conda config --system --set always_yes yes 21 | 22 | conda install -c timvideos gcc-riscv64-elf-nostdc openocd 23 | conda install meson 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, Zephyr on LiteX VexRiscv Developers 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third_party/litex"] 2 | path = third_party/litex 3 | url = https://github.com/enjoy-digital/litex.git 4 | [submodule "third_party/litedram"] 5 | path = third_party/litedram 6 | url = https://github.com/enjoy-digital/litedram.git 7 | [submodule "third_party/liteeth"] 8 | path = third_party/liteeth 9 | url = https://github.com/enjoy-digital/liteeth.git 10 | [submodule "third_party/litepcie"] 11 | path = third_party/litepcie 12 | url = https://github.com/enjoy-digital/litepcie.git 13 | [submodule "third_party/litesata"] 14 | path = third_party/litesata 15 | url = https://github.com/enjoy-digital/litesata.git 16 | [submodule "third_party/litescope"] 17 | path = third_party/litescope 18 | url = https://github.com/enjoy-digital/litescope.git 19 | [submodule "third_party/litevideo"] 20 | path = third_party/litevideo 21 | url = https://github.com/enjoy-digital/litevideo.git 22 | [submodule "third_party/migen"] 23 | path = third_party/migen 24 | url = https://github.com/m-labs/migen.git 25 | [submodule "third_party/litex-renode"] 26 | path = third_party/litex-renode 27 | url = https://github.com/litex-hub/litex-renode.git 28 | [submodule "third_party/nmigen"] 29 | path = third_party/nmigen 30 | url = https://github.com/m-labs/nmigen.git 31 | [submodule "third_party/litex-boards"] 32 | path = third_party/litex-boards 33 | url = https://github.com/litex-hub/litex-boards.git 34 | [submodule "third_party/litespi"] 35 | path = third_party/litespi 36 | url = https://github.com/litex-hub/litespi.git 37 | [submodule "third_party/liteiclink"] 38 | path = third_party/liteiclink 39 | url = https://github.com/enjoy-digital/liteiclink.git 40 | [submodule "litesata"] 41 | path = litesata 42 | url = https://github.com/enjoy-digital/litesata.git 43 | [submodule "third_party/pythondata-cpu-vexriscv"] 44 | path = third_party/pythondata-cpu-vexriscv 45 | url = https://github.com/litex-hub/pythondata-cpu-vexriscv 46 | [submodule "third_party/pythondata-software-compiler_rt"] 47 | path = third_party/pythondata-software-compiler_rt 48 | url = https://github.com/litex-hub/pythondata-software-compiler_rt.git 49 | [submodule "third_party/pythondata-software-picolibc"] 50 | path = third_party/pythondata-software-picolibc 51 | url = https://github.com/litex-hub/pythondata-software-picolibc.git 52 | [submodule "third_party/litei2c"] 53 | path = third_party/litei2c 54 | url = https://github.com/litex-hub/litei2c 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Zephyr-on-litex-vexriscv 2 | ======================== 3 | 4 | Zephyr on LiteX VexRiscv is a LiteX SoC builder for the `litex_vexriscv` platform in Zephyr. Currently it supports [Digilent Arty A7-35T Development Board](https://store.digilentinc.com/arty-a7-artix-7-fpga-development-board-for-makers-and-hobbyists) and [SDI MIPI Video Converter](https://github.com/antmicro/sdi-mipi-video-converter). 5 | 6 | Prerequisites 7 | ------------ 8 | 9 | First, if you want to run Zephyr on Digilent Arty, you have to install the F4PGA toolchain. It can be done by following instructions in [this tutorial](https://f4pga-examples.readthedocs.io/en/latest/getting.html). 10 | For SDI MIPI Video Converter - install oxide (yosys+nextpnr) toolchain by following [these instructions](https://github.com/gatecat/prjoxide#getting-started---complete-flow). 11 | 12 | Then, clone and enter the Zephyr-on-litex-vexriscv repository: 13 | 14 | ```bash 15 | git clone https://github.com/litex-hub/zephyr-on-litex-vexriscv.git && cd zephyr-on-litex-vexriscv 16 | ``` 17 | 18 | Get all required submodules and packages, and run the install script: 19 | ```bash 20 | git submodule update --init --recursive 21 | apt-get install build-essential bzip2 python3 python3-dev python3-pip 22 | ./install.sh 23 | ``` 24 | 25 | Build 26 | ----- 27 | Build the bitstream by following these steps: 28 | 29 | * Add LiteX to path: 30 | ```bash 31 | source ./init 32 | ``` 33 | * Prepare F4PGA environment (for Digilent Arty target): 34 | ```bash 35 | export F4PGA_INSTALL_DIR="path/to/f4pga" 36 | FPGA_FAM="xc7" 37 | export PATH="$F4PGA_INSTALL_DIR/$FPGA_FAM/install/bin:$PATH"; 38 | source "$F4PGA_INSTALL_DIR/$FPGA_FAM/conda/etc/profile.d/conda.sh" 39 | conda activate $FPGA_FAM 40 | ``` 41 | * Finally build the bitstream: 42 | 43 | For Digilent Arty board: 44 | ```bash 45 | ./make.py --board=arty --build 46 | ``` 47 | For SDI MIPI board: 48 | ```bash 49 | ./make.py --board=sdi_mipi_bridge --build --toolchain=oxide 50 | ``` 51 | 52 | Build options 53 | ----- 54 | | Option | Help | 55 | |---|---| 56 | | --toolchain | FPGA toolchain | 57 | | --board | FPGA board | 58 | | --build | build bitstream | 59 | | --variant | FPGA board variant | 60 | | --load | load bitstream | 61 | | --with-ethernet | Enable ethernet | 62 | | --with_i2s | Enable i2s | 63 | | --sys-clk-freq | System clock frequency | 64 | | --with_spi | Enable SPI | 65 | | --with_spi_flash | Enable SPI flash | 66 | | --with_i2c | Enable I2C (bitbang driver) | 67 | | --with_litei2c | Enable I2C via [LiteI2C](https://github.com/litex-hub/litei2c) | 68 | | --with_pwm | Enable PWM | 69 | | --spi-data-width | SPI data width | 70 | | --spi-clk-freq | SPI clock frequency | 71 | | --spi_flash_rate | SPI flash rate | 72 | | --with_mmcm | Enable MMCM | 73 | | --local-ip | local IP address | 74 | | --remote-ip | remote IP address | 75 | 76 | Load bitstream 77 | -------------- 78 | Connect your board using the serial port and load the bitstream: 79 | 80 | For Digilent Arty board: 81 | ```bash 82 | source ./init 83 | ./make.py --board=arty --load 84 | ``` 85 | 86 | For SDI MIPI board: 87 | ```bash 88 | source ./init 89 | ./make.py --board=sdi_mipi_bridge --load 90 | ``` 91 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI builds 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | Bitstream-build: 7 | runs-on: ubuntu-22.04 8 | steps: 9 | - uses: actions/checkout@v4 10 | with: 11 | submodules: recursive 12 | 13 | - name: Install dependencies 14 | run: | 15 | sudo apt-get update 16 | sudo apt-get install -y python3-pip bzip2 cmake build-essential clang bison flex tcl-dev libffi-dev mercurial graphviz xdot pkg-config python3 libftdi-dev python3-dev libeigen3-dev zlib1g-dev 17 | sudo apt-get install -y libboost-dev libboost-filesystem-dev libboost-thread-dev libboost-program-options-dev libboost-iostreams-dev libboost-dev libboost-system-dev libboost-python-dev libboost-filesystem-dev 18 | sudo apt-get install -y gcc-riscv64-unknown-elf 19 | 20 | - name: Install OSS CAD tools 21 | run: | 22 | curl -s https://api.github.com/repos/YosysHQ/oss-cad-suite-build/releases/latest \ 23 | | grep "browser_download_url.*oss-cad-suite-linux-x64-" \ 24 | | cut -d : -f 2,3 \ 25 | | tr -d \" \ 26 | | wget -qi - 27 | tar -xf oss-cad-suite-linux-x64-*.tgz 28 | rm -v oss-cad-suite-linux-x64-*.tgz 29 | 30 | - name: Build bitstream 31 | run: | 32 | source oss-cad-suite/environment 33 | source ./init 34 | pip3 install packaging meson ninja 35 | echo $PATH 36 | ./make.py --board=sdi_mipi_bridge --toolchain=oxide --build --csr-json csr.json --with_all 37 | 38 | - name: Generate dts and config 39 | run: ./third_party/litex/litex/tools/litex_json2dts_zephyr.py --dts overlay.dts --config overlay.config csr.json 40 | 41 | - uses: actions/upload-artifact@v4 42 | with: 43 | name: ${{github.job}} 44 | path: | 45 | ./build/antmicro_sdi_mipi_video_converter/gateware/antmicro_sdi_mipi_video_converter.bit 46 | ./overlay.dts 47 | ./overlay.config 48 | 49 | Zephyr-build: 50 | runs-on: ubuntu-24.04 51 | needs: Bitstream-build 52 | steps: 53 | - uses: actions/download-artifact@v4 54 | with: 55 | name: Bitstream-build 56 | 57 | - name: Install dependencies 58 | run: | 59 | sudo apt update 60 | sudo apt-get install -y --no-install-recommends git cmake ninja-build gperf \ 61 | ccache dfu-util device-tree-compiler wget \ 62 | python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ 63 | make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 python3-venv 64 | 65 | - name: Create Python virtual environment 66 | run: | 67 | python3 -m venv .venv 68 | source .venv/bin/activate 69 | echo "VIRTUAL_ENV=${VIRTUAL_ENV}" >> $GITHUB_ENV 70 | echo "${VIRTUAL_ENV}/bin" >> $GITHUB_PATH 71 | shell: bash 72 | 73 | - name: Prepare Zephyr 74 | run: | 75 | pip install west 76 | west init zephyrproject 77 | cd zephyrproject/ 78 | west config manifest.group-filter -- -hal,-tools,-bootloader,-babblesim 79 | west config manifest.project-filter -- -nrf_hw_models 80 | west config --global update.narrow true 81 | west update 82 | west zephyr-export 83 | west packages pip --install 84 | cd .. 85 | 86 | - name: Install Zephyr SDK 87 | run: | 88 | cd zephyrproject/zephyr 89 | west sdk install -H -t riscv64-zephyr-elf 90 | cd ../../ 91 | 92 | - name: Build Zephyr App 93 | run: | 94 | cd zephyrproject/zephyr 95 | cat ../../Bitstream-build/overlay.config | xargs west build -b litex_vexriscv samples/philosophers/ -- -DDTC_OVERLAY_FILE= ../../Bitstream-build/overlay.dts 96 | cd ../../ 97 | 98 | - uses: actions/upload-artifact@v4 99 | with: 100 | name: ${{github.job}} 101 | path: ./zephyrproject/zephyr/build/zephyr/zephyr.bin 102 | -------------------------------------------------------------------------------- /soc_zephyr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import argparse 5 | 6 | from migen import * 7 | 8 | from litex.soc.integration.soc import * 9 | from litex.soc.cores.i2s import * 10 | from litex.soc.cores.gpio import * 11 | from litex.soc.cores.pwm import PWM 12 | from litex.soc.cores.spi import SPIMaster 13 | from litex.soc.cores.bitbang import I2CMaster 14 | from litex_boards.platforms import digilent_arty as arty_platform 15 | from litex.soc.cores.gpio import GPIOOut, GPIOIn 16 | 17 | from liteeth.phy.mii import LiteEthPHYMII 18 | 19 | # Helpers ------------------------------------------------------------------------------------------ 20 | 21 | def platform_request_all(platform, name): 22 | from litex.build.generic_platform import ConstraintError 23 | r = [] 24 | while True: 25 | try: 26 | r += [platform.request(name, len(r))] 27 | except ConstraintError: 28 | break 29 | if r == []: 30 | raise ValueError 31 | return r 32 | 33 | # SoCZephyr ----------------------------------------------------------------------------------------- 34 | 35 | def SoCZephyr(soc_cls, **kwargs): 36 | class _SoCZephyr(soc_cls): 37 | csr_map = {**soc_cls.csr_map, **{ 38 | "ctrl": 0, # addr: 0xe0000000 39 | "uart": 3, # addr: 0xe0001800 40 | "spi": 4, # addr: 0xe0002000 41 | "timer0": 5, # addr: 0xe0002800 42 | "sdram": 6, # addr: 0xe0003000 43 | "uartphy": 7, # addr: 0xe0004000 44 | "mmcm": 9, # addr: 0xe0004800 45 | "i2c0": 10, # addr: 0xe0005000 46 | "rgb_led_r0": 14, # addr: 0xe0007000 47 | "ethphy": 16, # addr: 0xe0008000 48 | "ethmac": 19, # addr: 0xe0009800 49 | "i2s_rx": 21, # addr: 0xe000a800 50 | "i2s_tx": 22, # addr: 0xe000b000 51 | "ddrphy": 23, # addr: 0xe000b800 52 | "spiflash": 24, # addr: 0xe000c000 53 | "watchdog0": 26, # addr: 0xe000d000 54 | "litei2c": 27, # addr: 0xe000d800 55 | }} 56 | 57 | interrupt_map = {**soc_cls.interrupt_map, **{ 58 | "timer0": 1, 59 | "uart": 2, 60 | "ethmac": 3, 61 | "i2s_rx": 6, 62 | "i2s_tx": 7, 63 | "watchdog0": 8, 64 | "spiflash": 9, 65 | "litei2c": 10, 66 | }} 67 | 68 | mem_map_zephyr = { 69 | "rom": 0x00000000, 70 | "sram": 0x01000000, 71 | "main_ram": 0x40000000, 72 | "spiflash": 0x60000000, 73 | "ethmac": 0xb0000000, 74 | "i2s_rx": 0xb1000000, 75 | "i2s_tx": 0xb2000000, 76 | "csr": 0xe0000000, 77 | } 78 | 79 | def __init__(self, cpu_variant="standard", **kwargs): 80 | soc_cls.__init__(self, 81 | cpu_type="vexriscv", 82 | cpu_variant=cpu_variant, 83 | csr_data_width=32, 84 | max_sdram_size=0x10000000, # Limit mapped SDRAM to 256MB for now 85 | timer_uptime=True, 86 | **kwargs) 87 | soc_cls.mem_map.update(self.mem_map_zephyr) 88 | 89 | def add_rgb_led(self): 90 | rgb_led_pads = self.platform.request("rgb_led", 0) 91 | setattr(self.submodules, "rgb_led_r0", PWM(getattr(rgb_led_pads, 'r'))) 92 | 93 | def add_i2c(self): 94 | self.submodules.i2c0 = I2CMaster(self.platform.request("i2c", 0)) 95 | 96 | def add_i2s(self): 97 | self.platform.add_extension(arty_platform._i2s_pmod_io) 98 | i2s_mem_size = 0x40000 99 | # i2s rx 100 | self.submodules.i2s_rx = S7I2S( 101 | pads=self.platform.request("i2s_rx"), 102 | sample_width=24, 103 | frame_format=I2S_FORMAT.I2S_STANDARD, 104 | concatenate_channels=False, 105 | toolchain=kwargs["toolchain"] 106 | ) 107 | self.add_memory_region("i2s_rx", self.mem_map_zephyr["i2s_rx"], i2s_mem_size, type="io") 108 | self.add_wb_slave(self.mem_regions["i2s_rx"].origin, self.i2s_rx.bus, i2s_mem_size) 109 | # i2s tx 110 | self.submodules.i2s_tx = S7I2S( 111 | pads=self.platform.request("i2s_tx"), 112 | sample_width=24, 113 | frame_format=I2S_FORMAT.I2S_STANDARD, 114 | master=True, 115 | concatenate_channels=False, 116 | toolchain=kwargs["toolchain"] 117 | ) 118 | self.add_memory_region("i2s_tx", self.mem_map_zephyr["i2s_tx"], i2s_mem_size, type="io") 119 | self.add_wb_slave(self.mem_regions["i2s_tx"].origin, self.i2s_tx.bus, i2s_mem_size) 120 | 121 | self.comb += self.platform.request("i2s_rx_mclk").eq(self.cd_mmcm_clkout["i2s_rx"].clk) 122 | self.comb += self.platform.request("i2s_tx_mclk").eq(self.cd_mmcm_clkout["i2s_tx"].clk) 123 | 124 | def add_mmcm(self, freqs={}): 125 | self.cd_mmcm_clkout = {} 126 | self.submodules.mmcm = S7MMCM(speedgrade=-1) 127 | self.mmcm.register_clkin(self.crg.cd_sys.clk, self.clk_freq) 128 | 129 | self.add_constant("clkout_def_freq", int(self.clk_freq)) 130 | self.add_constant("clkout_def_phase", int(0)) 131 | self.add_constant("clkout_def_duty_num", int(50)) 132 | self.add_constant("clkout_def_duty_den", int(100)) 133 | self.add_constant("mmcm_lock_timeout", int(10)) 134 | self.add_constant("mmcm_drdy_timeout", int(10)) 135 | 136 | for n, key in enumerate(freqs): 137 | self.cd_mmcm_clkout.update({key : ClockDomain(name="cd_mmcm_clkout{}".format(n))}) 138 | self.mmcm.create_clkout(self.cd_mmcm_clkout[key], freqs[key]) 139 | 140 | for n in range(len(freqs), 7): 141 | key = "clk_{}".format(n) 142 | self.cd_mmcm_clkout.update({key : ClockDomain(name="cd_mmcm_clkout{}".format(n))}) 143 | self.mmcm.create_clkout(self.cd_mmcm_clkout[key], self.clk_freq) 144 | 145 | self.mmcm.expose_drp() 146 | self.comb += self.mmcm.reset.eq(self.mmcm.drp_reset.re) 147 | 148 | return _SoCZephyr(**kwargs) 149 | -------------------------------------------------------------------------------- /make.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import os 5 | 6 | from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict 7 | from litex.build.lattice.oxide import oxide_argdict, oxide_args 8 | from litex.soc.integration.builder import * 9 | 10 | from soc_zephyr import SoCZephyr 11 | 12 | # Board definition---------------------------------------------------------------------------------- 13 | 14 | class Board: 15 | def __init__(self, soc_cls): 16 | self.soc_cls = soc_cls 17 | self.mmcm_freq = {} 18 | self.bitstream_name="" 19 | self.bitstream_ext="" 20 | 21 | def load(self, soc, filename): 22 | prog = soc.platform.create_programmer() 23 | prog.load_bitstream(filename) 24 | 25 | def flash(self): 26 | raise NotImplementedError 27 | 28 | # Arty support ------------------------------------------------------------------------------------- 29 | 30 | class Arty(Board): 31 | def __init__(self): 32 | from litex_boards.targets import digilent_arty 33 | Board.__init__(self, digilent_arty.BaseSoC) 34 | self.mmcm_freq = { 35 | "i2s_rx" : 11.289e6, 36 | "i2s_tx" : 22.579e6, 37 | } 38 | self.bitstream_name="digilent_arty" 39 | self.bitstream_ext=".bit" 40 | 41 | class SDI_MIPI_Bridge(Board): 42 | def __init__(self): 43 | from litex_boards.targets import antmicro_sdi_mipi_video_converter 44 | Board.__init__(self, antmicro_sdi_mipi_video_converter.BaseSoC) 45 | self.bitstream_name="antmicro_sdi_mipi_video_converter" 46 | self.bitstream_ext=".bit" 47 | 48 | def load(self, soc, filename): 49 | prog = soc.platform.create_programmer(prog="ecpprog") 50 | prog.load_bitstream(filename) 51 | 52 | # Main --------------------------------------------------------------------------------------------- 53 | 54 | supported_boards = { 55 | # Xilinx 56 | "arty": Arty, 57 | "sdi_mipi_bridge": SDI_MIPI_Bridge, 58 | } 59 | 60 | def main(): 61 | description = "Zephyr on LiteX-VexRiscv\n\n" 62 | description += "Available boards:\n" 63 | for name in supported_boards.keys(): 64 | description += "- " + name + "\n" 65 | from litex.soc.integration.soc import LiteXSoCArgumentParser 66 | parser = LiteXSoCArgumentParser(description="LiteX SoC on Arty A7 and SDI-MIPI Bridge") 67 | parser.add_argument("--toolchain", default="symbiflow", help="FPGA toolchain - vivado, symbiflow or oxide (yosys+nextpnr).") 68 | parser.add_argument("--board", required=True, help="FPGA board") 69 | parser.add_argument("--build", action="store_true", help="build bitstream") 70 | parser.add_argument("--flash", action="store_true", help="Flash bitstream.") 71 | parser.add_argument("--variant", default=None, help="FPGA board variant") 72 | parser.add_argument("--load", action="store_true", help="load bitstream (to SRAM). set path to bitstream") 73 | parser.add_argument("--with_all", action="store_true", help="Enable all peripherals") 74 | parser.add_argument("--with_ethernet", action="store_true", help="Enable ethernet (Arty target only)") 75 | parser.add_argument("--with_etherbone", action="store_true", help="Enable etherbone (Arty target only)") 76 | parser.add_argument("--with_i2s", action="store_true", help="Enable i2s (Arty target only)") 77 | parser.add_argument("--sys-clk-freq", default=100e6, help="System clock frequency.") 78 | parser.add_argument("--with_spi", action="store_true", help="Enable spi (Arty target only)") 79 | parser.add_argument("--with_spi_flash", action="store_true", help="Enable spi flash (Arty target only)") 80 | i2copts = parser.add_mutually_exclusive_group() 81 | i2copts.add_argument("--with_i2c", action="store_true", help="Enable i2c (Arty target only)") 82 | i2copts.add_argument("--with_litei2c", action="store_true", help="Enable i2c via litei2c (Arty target only)") 83 | parser.add_argument("--with_pwm", action="store_true", help="Enable pwm (Arty target only)") 84 | parser.add_argument("--spi-data-width", type=int, default=8, help="SPI data width (maximum transfered bits per xfer, Arty target only)") 85 | parser.add_argument("--spi-clk-freq", type=int, default=1e6, help="SPI clock frequency (Arty target only)") 86 | parser.add_argument("--spi_flash_rate", default="1:1", help="SPI flash rate, can be 1:1 or 1:2 (Arty target only)") 87 | parser.add_argument("--with_mmcm", action="store_true", help="Enable mmcm (Arty target only)") 88 | parser.add_argument("--with_watchdog", action="store_true", help="Enable watchdog") 89 | parser.add_argument("--watchdog_width", type=int, default=32, help="Watchdog width") 90 | parser.add_argument("--watchdog_reset_delay", type=int, default=None, help="Watchdog reset delay") 91 | parser.add_argument("--etherbone-ip", default="192.168.1.50", help="etherbone IP address (Arty target only)") 92 | parser.add_argument("--local-ip", default="192.168.1.51", help="local IP address (Arty target only)") 93 | parser.add_argument("--remote-ip", default="192.168.1.100", help="remote IP address of TFTP server (Arty target only)") 94 | builder_args(parser) 95 | vivado_build_args(parser) 96 | oxide_args(parser) 97 | args = parser.parse_args() 98 | 99 | if args.with_all: 100 | args.with_ethernet = True 101 | args.with_etherbone = True 102 | args.with_i2s = True 103 | args.with_spi = True 104 | args.with_spi_flash = True 105 | args.with_i2c = True 106 | args.with_pwm = True 107 | args.with_mmcm = True 108 | args.with_watchdog = True 109 | 110 | if args.board == "all": 111 | board_names = list(supported_boards.keys()) 112 | else: 113 | args.board = args.board.lower() 114 | board_names = [args.board.replace(" ", "_")] 115 | 116 | soc_kwargs = {"integrated_rom_size": 0xfa00} 117 | soc_kwargs.update(toolchain=args.toolchain) 118 | soc_kwargs.update(with_jtagbone=False) 119 | 120 | if args.variant is not None: 121 | soc_kwargs.update(variant=args.variant) 122 | if args.sys_clk_freq is not None: 123 | soc_kwargs.update(sys_clk_freq=int(float(args.sys_clk_freq))) 124 | 125 | for board_name in board_names: 126 | if board_name not in supported_boards: 127 | print("Board {} is not supported currently".format(board_name)) 128 | continue 129 | board = supported_boards[board_name]() 130 | 131 | soc = SoCZephyr(board.soc_cls, **soc_kwargs) 132 | 133 | if args.with_watchdog: 134 | soc.add_watchdog(name="watchdog0" ,width=args.watchdog_width, reset_delay=args.watchdog_reset_delay) 135 | 136 | if board_name == "arty": 137 | if args.with_ethernet or args.with_etherbone: 138 | from liteeth.phy.mii import LiteEthPHYMII 139 | soc.ethphy = LiteEthPHYMII( 140 | clock_pads = soc.platform.request("eth_clocks"), 141 | pads = soc.platform.request("eth")) 142 | if args.with_etherbone: 143 | soc.add_etherbone(phy=soc.ethphy, ip_address=args.etherbone_ip, with_ethmac=args.with_ethernet, ethmac_local_ip=args.local_ip, ethmac_remote_ip=args.remote_ip) 144 | elif args.with_ethernet: 145 | soc.add_ethernet(phy=soc.ethphy, local_ip=args.local_ip, remote_ip=args.remote_ip) 146 | if args.with_mmcm: 147 | soc.add_mmcm(board.mmcm_freq) 148 | if args.with_pwm: 149 | soc.add_rgb_led() 150 | if args.with_spi: 151 | soc.add_spi_master(name="spi", data_width=args.spi_data_width, spi_clk_freq=args.spi_clk_freq) 152 | if args.with_spi_flash: 153 | from litespi.modules import S25FL128L 154 | from litespi.opcodes import SpiNorFlashOpCodes as Codes 155 | assert args.spi_flash_rate in ["1:1", "1:2"] 156 | soc.add_spi_flash(mode="4x", module=S25FL128L(Codes.READ_1_1_4), rate=args.spi_flash_rate, with_master=True) 157 | if args.with_i2c: 158 | soc.add_i2c() 159 | if args.with_litei2c: 160 | soc.add_i2c_master(name="litei2c", pads=soc.platform.request("i2c", 0)) 161 | if args.with_i2s: 162 | if not args.with_mmcm: 163 | print("Adding mmcm implicitly, cause i2s core needs special clk signals") 164 | soc.add_mmcm(board.mmcm_freq) 165 | soc.add_i2s() 166 | 167 | build_dir = os.path.join("build", board.bitstream_name) 168 | 169 | if args.build: 170 | builder = Builder(soc, **builder_argdict(args)) 171 | if args.toolchain == "vivado": 172 | builder_kwargs = vivado_build_argdict(args) 173 | elif args.toolchain == "oxide": 174 | builder_kwargs = oxide_argdict(args) 175 | else: 176 | builder_kwargs = {} 177 | builder.build(**builder_kwargs, run=args.build) 178 | 179 | if args.load: 180 | board.load(soc, filename=os.path.join(build_dir, "gateware", board.bitstream_name + board.bitstream_ext)) 181 | 182 | if args.flash: 183 | prog = soc.platform.create_programmer() 184 | prog.flash(0, os.path.join(build_dir, "gateware", board.bitstream_name + board.bitstream_ext)) 185 | 186 | if __name__ == "__main__": 187 | main() 188 | --------------------------------------------------------------------------------