Tutorial 1 - LiteX in Simulation
Goal
By the end of this tutorial, you should be able to: install LiteX, build a small RISC-V SoC (CPU + UART), boot it in Verilator-based simulation, and run two programs on it - a pre-built example, and a small C program you write yourself - entirely in simulation, before touching any hardware.
Working in simulation first (same principle as Lab 2's Verilator testbench) lets you debug the software/toolchain flow without the extra variables a real board introduces (USB drivers, pin mapping, physical timing).
Background: what LiteX gives you for free
Your Project 1-2 core is built one instruction, one peripheral, at a time. LiteX takes the opposite approach: it is a SoC generator - a Python library (built on Migen, a hardware-description DSL embedded in Python) that assembles a working system from existing, tested components:
- A RISC-V CPU (this tutorial uses VexRiscv, LiteX's most common default softcore).
- A Wishbone-based interconnect connecting the CPU to memory and peripherals - conceptually the same idea as the memory-mapped bus you build in Project 2, just already built and tested.
- Standard peripherals (UART, timer, GPIO) with C driver headers auto-generated from the SoC's actual register map (no hand-written memory map like Project 2's - LiteX generates
csr.hfor you from the Python SoC description). - A BIOS that boots over the UART, prints a banner, and can load and run a separate firmware image sent over serial - this is what "boots" when you power on a LiteX design, before your own program runs.
1. Install LiteX
LiteX is installed via its own bootstrap script (not a package manager package - it clones several repositories: LiteX itself, litex-boards, Migen, and the VexRiscv CPU sources):
This installs LiteX and its dependencies into your user Python environment. Note: the rest of this course uses uv for all Python tooling (see Toolchain) - litex_setup.py does not use uv natively. Check with the instructor whether a uv-compatible install path is documented by the time you read this; if not, an isolated venv/pipx install (not a bare system-wide pip install) is the safer fallback.
Confirm the install:
2. Confirm your RISC-V cross-compiler works - and pin it explicitly
LiteX needs a RISC-V GCC toolchain to compile firmware. You likely already have one from Lab 2/Project 1 (riscv-none-elf-gcc, xPack). Check it's on your PATH:
This check alone isn't enough. LiteX auto-detects a toolchain by trying a fixed list of common prefixes (riscv64-unknown-elf-, riscv-none-elf-, and others) and silently uses the first one it finds on your PATH - if you have more than one RISC-V GCC installed (easy to end up with, e.g. one from Homebrew and one from xPack), LiteX may pick a different one than you expect, with no warning. Pin it explicitly instead:
This forces LiteX to use the xPack toolchain you already have from Lab 2 - no second RISC-V GCC install needed for this track.
If you activated OSS CAD Suite via its environment/activate script (rather than the plain PATH export Lab 2 recommends), double-check python3 still resolves to the Python environment where you installed LiteX (step 1) - that script bundles its own Python, which can shadow the one with litex installed if its bin/ directory ends up ahead of your Python on PATH. If litex_sim --help (step 1) stops working after activating OSS CAD Suite, this is the first thing to check: make sure your LiteX-capable Python resolves before OSS CAD Suite's bin/ directory on PATH, not after.
3. Build and boot a SoC in simulation
LiteX ships a generic simulation target that doesn't require any specific board:
This should: elaborate the SoC in Migen, generate Verilog, compile it with Verilator (the same simulator you used in Lab 2, driven by LiteX instead of your own testbench), and boot it. You should see the LiteX BIOS banner print directly in your terminal, followed by a boot sequence and a litex> prompt.
This BIOS is your first "ready-made example program" - explore it a little:
4. Write and run your own program
Now replace the BIOS's default behavior with a small C program of your own. LiteX's build process generates a software/ directory containing csr.h (register definitions for every peripheral in your SoC) and a demo main.c template you can start from.
Write a minimal program (a "hello world" is enough) using LiteX's libbase for serial output:
(#include <stdio.h> is required for printf - easy to forget since the other two headers look like they'd be enough.)
Build it against the generated headers (LiteX's software Makefile under the build output directory handles the cross-compilation flags).
Loading it into a running simulation needs one extra piece. The plain litex_sim command from step 3 wires the simulated UART directly to your terminal's own stdin/stdout - there's no separate "port" a second tool could attach to, so a bare litex_term --kernel firmware.bin <port> has nothing to point at. Instead, run the simulation with its UART exposed over a TCP socket, using litex_sim_tcp_serial.py (a copy of LiteX's own simulation target with one addition: a --serial-tcp-port option) - download it into your working directory, then:
If you attach after the simulation has already booted (likely, since it doesn't wait for a client), you won't see the original boot banner - type reboot at the point you'd expect a litex> prompt to trigger a fresh boot you can actually watch. Then load your program the same way as before:
Confirm your own printf output appears in the terminal, replacing the BIOS prompt.
Checklist
- LiteX installed;
litex_sim --helpruns. -
LITEX_ENV_CC_TRIPLE=riscv-none-elfset, confirmed via the build log showingriscv-none-elf-gcc(not a different toolchain) as the compiler used. - A VexRiscv-based SoC boots in simulation; the BIOS banner and
litex>prompt appear. - A new C program you wrote is compiled and loaded into the running simulation via
litex_sim_tcp_serial.py+litex_term socket://.... - Your program's own output (not the BIOS's) is visible in the terminal.
Next
Tutorial 2 repeats both programs - the BIOS and your own - on your real Tang Nano 9K.