- Shell 55.3%
- Dockerfile 44.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
No display, no capabilities or route out, rootless only; --usb passes just the JTAG adapters. Used by the pi-docker --fpga broker. |
||
| .gitignore | ||
| altera_docker.sh | ||
| Arrow_USB_Programmer_2.5.1_linux64.zip | ||
| Dockerfile | ||
| Dockerfile.extras | ||
| entrypoint.sh | ||
| llm_section_context_recap.md | ||
| README.org | ||
| xpack-riscv-none-elf-gcc-12.5.0-1-linux-x64.tar.gz.sha | ||
- Prerequisites
- Step 1: Save the Dockerfile & Prepare Your Folder
- Step 2: Build the Docker Image
- Step 3: Get the free Questa license (one time)
- Step 4: Run the Docker Container
- Step 5: Develop Inside the Container
- Image tags
- Dependencies that no installer provides
- Licensed IP
- Step 6: Exiting the Container
Prerequisites
Before you begin, ensure you have:
- Docker installed and running on your Linux system.
-
Downloaded the following files and placed them in the same directory as your Dockerfile (all from the Quartus Prime Lite 22.1std download page):
- QuartusLiteSetup-22.1std.0.915-linux.run
- QuestaSetup-22.1std.0.915-linux.run
- cyclone10lp-22.1std.0.915.qdz
Prefer the individual .run downloads over the "Complete Download" .tar:
they add up to far less than the ~6 GB tar (which bundles every device
family), and the Dockerfile references the .run filenames directly. Check
that the downloaded filenames carry the same build number (0.915) as the
COPY lines in the Dockerfile — if Intel has bumped the build, update the
filenames there and in this README.
Fallback if an individual file is ever unavailable: the Complete .tar
contains all of them under components/ — extract it somewhere temporary
(NOT next to the Dockerfile, it would bloat the Docker build context), copy
out the needed files, delete the rest.
Step 1: Save the Dockerfile & Prepare Your Folder
Save the updated Dockerfile code into a file named Dockerfile. Make sure the Quartus installer and device files are in this same directory. Your directory structure should look like this:
altera-dev-env/ ├── Dockerfile ├── entrypoint.sh ├── altera_docker.sh ├── QuartusLiteSetup-22.1std.0.915-linux.run ├── QuestaSetup-22.1std.0.915-linux.run └── cyclone10lp-22.1std.0.915.qdz
Step 2: Build the Docker Image
Navigate to the directory containing your Dockerfile and the installer files in a terminal. Run the following command to build the Docker image.
# Build the image, passing your user/group ID to avoid permission issues
sudo docker build \
--no-cache \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
-t quartus-c10lp .
This build process will be much faster as it uses your local files instead of downloading them.
Step 3: Get the free Questa license (one time)
Quartus Lite itself needs no license, but two things do: Questa-Intel FPGA Starter Edition, and any licensed IP in a design (see Licensed IP below). Both are node-locked to a NIC MAC address (FlexLM host ID), so one invented MAC covers both and the same pinning trick works for each.
- Invent a locally-administered MAC address (second hex digit must be 2, 6,
a, or e — e.g.
6e:df:de:44:ec:7e). Do NOT use a real interface's MAC: registering an invented one and pinning the container to it makes the license portable across machines (same trick as xilinx-dev-env). - In the Intel FPGA Self-Service Licensing Center, choose
"Sign up for Evaluation or Free Licenses" and select
Questa-Intel FPGA Starter Edition (SW-QUESTA). When asked for a computer
with a NIC ID, register your invented MAC without colons (
6edfde44ec7e). - Intel emails you a
.datlicense file. Place it at:
mkdir -p ~/dev/fpga/licenses
cp LR-xxxxxx_License.dat ~/dev/fpga/licenses/questa_license.dat
-
Edit the two variables at the top of
altera_docker.sh:LICENSE_MAC— your invented MAC, formatted with colons. The launcher passes it as Docker's--mac-addressso FlexLM always sees the licensed host ID (this is also why the container uses a bridge network instead of--net=host— Docker can only set a MAC on an interface it owns).LICENSE_FILE— path to the license inside the container. The default/licenses/questa_license.datalready matches the copy step above.
Verify from inside the container (./altera_docker.sh -c):
vsim -c -do "quit" # should start without a license error
Step 4: Run the Docker Container
Use the launcher — it handles X11 permission (xhost +local:docker), the
license MAC/file, USB Blaster passthrough, and mounting the current directory
at /workspace:
./altera_docker.sh # Quartus GUI
./altera_docker.sh --cli # bash shell with the tool environment sourced
./altera_docker.sh --sim # Questa GUI (vsim)
Run it from your project directory — whatever directory you launch from
becomes /workspace inside the container.
Rootless Docker (no sudo)
The launcher uses the rootless Docker daemon when its socket
($XDG_RUNTIME_DIR/docker.sock) is up and holds quartus-c10lp:latest;
otherwise it falls back to the system daemon. The banner's Docker : line says
which one ran. Under rootless the container runs as root, which maps to your
host user, so files written to /workspace stay owned by you.
The image must exist in the rootless daemon's own store. Copy it from the
system daemon through a file, not a pipe — a sudo prompt written to stdout
corrupts a docker save | docker load stream:
sudo docker save -o quartus-c10lp.tar quartus-c10lp:latest
sudo chown $USER quartus-c10lp.tar
DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock docker load -i quartus-c10lp.tar
rm quartus-c10lp.tar
--rootful forces the system daemon. Use it for JTAG programming until USB
passthrough is proven under rootless.
Note: xhost +local:docker is generally safe, but it allows any local
container started by your user to connect to your display. Revoke it later
with xhost -local:docker.
Step 5: Develop Inside the Container
After running ./altera_docker.sh --cli, your terminal prompt will change, indicating you are now inside the container.
You can now use all the installed tools:
Navigate to your project:
cd /workspace
ls # You should see your project files here
Compile and Simulate with GHDL:
# Analyze/compile VHDL files
ghdl -a my_design.vhd my_testbench.vhd
# Elaborate the testbench
ghdl -e my_testbench
# Run the simulation and create a VCD waveform file
ghdl -r my_testbench --vcd=my_testbench.vcd
Simulate with Questa:
GHDL + GTKWave remain the fast iteration loop; Questa is the vendor-accurate simulator with Intel's precompiled device libraries.
# Compile and run a VHDL testbench in batch mode
vlib work
vcom my_design.vhd my_testbench.vhd
vsim -c my_testbench -do "run -all; quit"
# Or with the waveform GUI
vsim my_testbench
To have Quartus hand off to Questa automatically (Tools → Run Simulation Tool
/ NativeLink), add to your .qsf:
set_global_assignment -name EDA_SIMULATION_TOOL "Questa Intel FPGA (VHDL)"
Synthesize and Compile with Quartus:
(Assuming you have a Quartus project file, e.g., my_quartus_project.qpf)
# Run the entire Quartus compilation flow from the command line
quartus_sh --flow compile my_quartus_project
This will generate your programming file (.sof) in the output_files directory.
Convert Programming File:
openFPGALoader often works best with the Raw Binary File (.rbf) format. Use the Quartus conversion tool to create it from the .sof file.
quartus_cpf -c output_files/my_quartus_project.sof output_files/my_quartus_project.rbf
Program your FPGA with openFPGALoader:
First, detect the board to make sure it's connected and recognized:
openFPGALoader --detect
Then, upload your generated bitstream file:
openFPGALoader -b cyclone10lp your_firmware.rbf
(You may need to adjust the –board or other flags depending on your specific Cyclone 10 LP board.)
Image tags
altera_docker.sh always launches quartus-c10lp:latest. Each time
Dockerfile.extras adds something, the image it replaces is kept under a
pre-<change> tag so a regression can be bisected without a 35 GB rebuild.
| Tag | What it is |
|---|---|
latest |
current — carries the Arrow driver, the Nios II library fixes and the RISC-V toolchain |
pre-niosv |
before the RISC-V toolchain was added |
arrow |
the Arrow driver layer, same image pre-niosv points at |
pre-arrow |
before the Arrow USB Programmer library |
nios-fix, pre-niosfix |
around the libfl.so.2 / ncurses fix that unblocked Nios II BSP builds |
Rebuild and promote with:
docker build -f Dockerfile.extras -t quartus-c10lp:<change> .
docker tag quartus-c10lp:latest quartus-c10lp:pre-<change>
docker tag quartus-c10lp:<change> quartus-c10lp:latest
Dependencies that no installer provides
Three things this environment needs that are not part of any Intel download. Each one, when absent, fails in a way that points somewhere else entirely.
Arrow USB Programmer hardware library
Quartus ships no plugin for the FT2232H blaster on Trenz boards. Without it
jtagconfig reports "No JTAG hardware available" on a board that is powered,
connected and enumerating correctly, and nios2-terminal, nios2-download and
quartus_pgm are all unavailable. Version 2.5.1 (linux64) from the Trenz
download area, baked in by Dockerfile.extras.
It also needs a HOST udev rule releasing ftdi_sio from interface 0 — an
image cannot fix that. The rule must match on the interface string, not on the
bound driver: at add time nothing is bound yet, so a DRIVERS="ftdi_sio"=
match never fires and the rule silently does nothing while looking correct.
RISC-V bare-metal toolchain (Nios V only)
No Intel installer ships one. The Nios V BSP writes riscv32-unknown-elf-gcc
into its own generated toolchain.cmake with a plain set(), which shadows any
CMake cache override, so the compiler has to exist under exactly that name.
niosv-shell looks for Intel's RiscFree under $ACDS_ROOT/riscfree and, not
finding it, prints an INFO line and carries on — so the failure surfaces much
later as a missing compiler inside a generated CMake build.
xPack riscv-none-elf-gcc 12.5.0-1 is used instead: freely redistributable, no
account needed, ships newlib, and rv32ia/ilp32 is an exact multilib with a
matching libc.a. The tarball is too large to commit; fetch it next to the
Dockerfile before building, and check it against the committed .sha:
V=12.5.0-1
curl -LO https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v$V/xpack-riscv-none-elf-gcc-$V-linux-x64.tar.gz
sha256sum -c xpack-riscv-none-elf-gcc-$V-linux-x64.tar.gz.sha
GCC 12 matches the major version of the Nios II EDS compiler
this BSP generation was written alongside. Installed to /opt/riscv-none-elf
and symlinked to the riscv32-unknown-elf- prefix by Dockerfile.extras.
Note this does NOT fix the zicsr problem: binutils 2.38 moved the CSR
instructions out of the base RISC-V I extension, so the BSP's own crt0.S needs
-march=rv32ia_zicsr. That is a BSP setting the consuming project declares —
see mk/README.md.
Container library additions
The base image lacks libfl.so.2, which aborts nios2-elf-ar and so every
Nios II BSP build, and the ncurses 5 ABI pair nios2-elf-gdb needs. Both come
from Dockerfile.extras.
Licensed IP
Quartus Lite needs no license to run, but it will not emit a programming file for a design containing licensed IP. Two cases met on this setup, and they fail differently:
| IP | FlexLM feature | Without a license |
|---|---|---|
| Triple-Speed Ethernet | altera_eth_tse |
builds a time-limited .sof that halts after ~1 hour and cannot be converted to .pof, .jic or .rbf |
| Nios V/m | 6AF7_D036 |
no programming file at all — no evaluation mode exists for it |
The Nios V/m failure is the dangerous one. The design synthesises and fits,
quartus_asm reports "successful, 0 errors", and output_files/ simply has no
.sof in it. The diagnosis is Warning (115003) naming the unlicensed IP and
Warning (12192) saying it does not support IP Evaluation Mode. Check for the
artefact, not the exit status.
Presence in the Lite IP catalogue and a SUPPORTED_DEVICE_FAMILIES entry
naming your device say nothing about licensing. The only probe that answers the
question is running the assembler and looking for a programming file.
Using more than one license file
LM_LICENSE_FILE takes a colon-separated list, and altera_docker.sh passes
LICENSE_FILE straight through, so several node-locked files coexist:
LICENSE_FILE="/licenses/LR-182581_License.dat:/licenses/questa_license.dat"
Node-locked IP licenses come from the same Self-Service Licensing Center as the Questa one and are tied to the same invented MAC, so no second host ID is needed.
Step 6: Exiting the Container
When you are finished, simply type exit in the container's terminal. Because you used the –rm flag, the container will be automatically removed. Your project files in the mounted directory will remain untouched on your host machine.