Files
artiq-zynq/flake.nix
2026-01-09 13:14:45 +08:00

545 lines
16 KiB
Nix

{
description = "ARTIQ port to the Zynq-7000 platform";
inputs.artiq.url = git+https://github.com/m-labs/artiq.git;
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";
outputs = {
self,
zynq-rs,
artiq,
}: let
pkgs = import artiq.inputs.nixpkgs {
system = "x86_64-linux";
overlays = [(import zynq-rs.inputs.rust-overlay)];
};
zynqpkgs = zynq-rs.packages.x86_64-linux;
artiqpkgs = artiq.packages.x86_64-linux;
zynqRev = self.sourceInfo.rev or "unknown";
rust = zynq-rs.rust;
naerskLib = zynq-rs.naerskLib;
fastnumbers = pkgs.python3Packages.buildPythonPackage rec {
pname = "fastnumbers";
version = "5.1.0";
src = pkgs.python3Packages.fetchPypi {
inherit pname version;
sha256 = "sha256-4JLTP4uVwxcaL7NOV57+DFSwKQ3X+W/6onYkN2AdkKc=";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
};
artiq-netboot = pkgs.python3Packages.buildPythonPackage rec {
pname = "artiq-netboot";
version = "unstable-2020-10-15";
src = pkgs.fetchgit {
url = "https://git.m-labs.hk/m-labs/artiq-netboot.git";
rev = "04f69eb07df73abe4b89fde2c24084f7664f2104";
sha256 = "0ql4fr8m8gpb2yql8aqsdqsssxb8zqd6l65kl1f6s9845zy7shs9";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
};
ramda = pkgs.python3Packages.buildPythonPackage {
pname = "ramda";
version = "unstable-2020-04-11";
src = pkgs.fetchFromGitHub {
owner = "peteut";
repo = "ramda.py";
rev = "d315a9717ebd639366bf3fe26bad9e3d08ec3c49";
sha256 = "sha256-bmSt/IHDnULsZjsC6edELnNH7LoJSVF4L4XhwBAXRkY=";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
nativeBuildInputs = with pkgs.python3Packages; [pbr];
propagatedBuildInputs = with pkgs.python3Packages; [fastnumbers];
checkInputs = with pkgs.python3Packages; [pytest];
checkPhase = "pytest";
doCheck = false;
preBuild = ''
export PBR_VERSION=0.5.5
'';
};
migen-axi = pkgs.python3Packages.buildPythonPackage {
pname = "migen-axi";
version = "unstable-2023-01-06";
src = pkgs.fetchFromGitHub {
owner = "peteut";
repo = "migen-axi";
rev = "98649a92ed7d4e43f75231e6ef9753e1212fab41";
sha256 = "sha256-0kEHK+l6gZW750tq89fHRxIh3Gnj5EP2GZX/neWaWzU=";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
propagatedBuildInputs = with pkgs.python3Packages; [setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc];
checkInputs = with pkgs.python3Packages; [pytestCheckHook pytest-timeout];
# migen/misoc version checks are broken with pyproject for some reason
postPatch = ''
sed -i "1,4d" pyproject.toml
substituteInPlace pyproject.toml \
--replace '"migen@git+https://github.com/m-labs/migen",' ""
substituteInPlace pyproject.toml \
--replace '"misoc@git+https://github.com/m-labs/misoc.git",' ""
# pytest-flake8 is broken with recent flake8. Re-enable after fix.
substituteInPlace setup.cfg --replace '--flake8' ""
'';
};
binutils = {
platform,
target,
zlib,
}:
pkgs.stdenv.mkDerivation rec {
basename = "binutils";
version = "2.30";
name = "${basename}-${platform}-${version}";
src = pkgs.fetchurl {
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
};
configureFlags = ["--enable-shared" "--enable-deterministic-archives" "--target=${target}"];
outputs = ["out" "info" "man"];
depsBuildBuild = [pkgs.buildPackages.stdenv.cc];
buildInputs = [zlib];
enableParallelBuilding = true;
};
binutils-arm = pkgs.callPackage binutils {
platform = "arm";
target = "armv7-unknown-linux-gnueabihf";
};
# FSBL configuration supplied by Vivado 2020.1 for these boards:
fsblTargets = ["zc702" "zc706" "zed"];
sat_variants = [
# kasli-soc satellite variants
"satellite"
# zc706 satellite variants
"nist_clock_satellite"
"nist_qc2_satellite"
"acpki_nist_clock_satellite"
"acpki_nist_qc2_satellite"
"nist_clock_satellite_100mhz"
"nist_qc2_satellite_100mhz"
"acpki_nist_clock_satellite_100mhz"
"acpki_nist_qc2_satellite_100mhz"
];
board-package-set = {
target,
variant,
json ? null,
}: let
szl = zynqpkgs."${target}-szl";
fsbl = zynqpkgs."${target}-fsbl";
fwtype =
if builtins.elem variant sat_variants
then "satman"
else "runtime";
firmware = naerskLib.buildPackage rec {
name = "firmware";
src = ./src;
additionalCargoLock = "${rust}/lib/rustlib/src/rust/library/Cargo.lock";
singleStep = true;
nativeBuildInputs = [
pkgs.gnumake
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
pkgs.llvmPackages_20.llvm
pkgs.llvmPackages_20.clang-unwrapped
];
overrideMain = _: {
buildPhase = ''
export ZYNQ_REV=${zynqRev}
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include"
export ZYNQ_RS=${zynq-rs}
make TARGET=${target} GWARGS="${
if json == null
then "-V ${variant}"
else json
}" ${fwtype}
'';
installPhase = ''
mkdir -p $out $out/nix-support
cp ../build/${fwtype}.bin $out/${fwtype}.bin
cp ../build/firmware/armv7-none-eabihf/release/${fwtype} $out/${fwtype}.elf
echo file binary-dist $out/${fwtype}.bin >> $out/nix-support/hydra-build-products
echo file binary-dist $out/${fwtype}.elf >> $out/nix-support/hydra-build-products
'';
doCheck = false;
dontFixup = true;
};
};
gateware =
pkgs.runCommand "${target}-${variant}-gateware"
{
nativeBuildInputs = [
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
artiqpkgs.vivado
];
}
''
export ZYNQ_REV=${zynqRev}
python ${./src/gateware}/${target}.py -g build ${
if json == null
then "-V ${variant}"
else json
}
mkdir -p $out $out/nix-support
cp build/top.bit $out
echo file binary-dist $out/top.bit >> $out/nix-support/hydra-build-products
'';
# SZL startup
jtag =
pkgs.runCommand "${target}-${variant}-jtag" {}
''
mkdir $out
ln -s ${szl}/szl.elf $out
ln -s ${firmware}/${fwtype}.bin $out
ln -s ${gateware}/top.bit $out
'';
sd =
pkgs.runCommand "${target}-${variant}-sd"
{
buildInputs = [zynqpkgs.mkbootimage];
}
''
# Do not use "long" paths in boot.bif, because embedded developers
# can't write software (mkbootimage will segfault).
bifdir=`mktemp -d`
cd $bifdir
ln -s ${szl}/szl.elf szl.elf
ln -s ${firmware}/${fwtype}.elf ${fwtype}.elf
ln -s ${gateware}/top.bit top.bit
cat > boot.bif << EOF
the_ROM_image:
{
[bootloader]szl.elf
top.bit
${fwtype}.elf
}
EOF
mkdir $out $out/nix-support
mkbootimage boot.bif $out/boot.bin
echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products
'';
# FSBL startup
fsbl-sd =
pkgs.runCommand "${target}-${variant}-fsbl-sd"
{
buildInputs = [zynqpkgs.mkbootimage];
}
''
bifdir=`mktemp -d`
cd $bifdir
ln -s ${fsbl}/fsbl.elf fsbl.elf
ln -s ${gateware}/top.bit top.bit
ln -s ${firmware}/${fwtype}.elf ${fwtype}.elf
cat > boot.bif << EOF
the_ROM_image:
{
[bootloader]fsbl.elf
top.bit
${fwtype}.elf
}
EOF
mkdir $out $out/nix-support
mkbootimage boot.bif $out/boot.bin
echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products
'';
in
{
"${target}-${variant}-firmware" = firmware;
"${target}-${variant}-gateware" = gateware;
"${target}-${variant}-jtag" = jtag;
"${target}-${variant}-sd" = sd;
}
// (
if builtins.elem target fsblTargets
then {
"${target}-${variant}-fsbl-sd" = fsbl-sd;
}
else {}
);
gateware-sim = pkgs.stdenv.mkDerivation {
name = "gateware-sim";
nativeBuildInputs = [
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.artiq-build]))
];
phases = ["buildPhase"];
buildPhase = ''
python -m unittest discover ${self}/src/gateware -v
touch $out
'';
};
fmt-check = pkgs.stdenvNoCC.mkDerivation {
name = "fmt-check";
src = ./src;
nativeBuildInputs = [rust pkgs.gnumake];
phases = ["unpackPhase" "buildPhase"];
buildPhase = ''
export ZYNQ_RS=${zynq-rs}
make manifests
cargo fmt -- --check
touch $out
'';
};
# for hitl-tests
zc706-nist_qc2 = board-package-set {
target = "zc706";
variant = "nist_qc2";
};
zc706-acpki_nist_qc2 = board-package-set {
target = "zc706";
variant = "acpki_nist_qc2";
};
make-zc706-hitl-tests = { name, board-package, ddb_folder ? "examples" }: pkgs.stdenv.mkDerivation {
name = "zc706-hitl-tests-${name}";
__networked = true; # compatibility with old patched Nix
# breaks hydra, https://github.com/NixOS/hydra/issues/1216
#__impure = true; # Nix 2.8+
buildInputs = [
pkgs.netcat
pkgs.openssh
pkgs.rsync
artiqpkgs.artiq
artiq-netboot
zynqpkgs.zc706-szl
];
phases = ["buildPhase"];
buildPhase = ''
export NIX_SSHOPTS="-F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i /opt/hydra_id_ed25519"
LOCKCTL=$(mktemp -d)
mkfifo $LOCKCTL/lockctl
cat $LOCKCTL/lockctl | ${pkgs.openssh}/bin/ssh \
$NIX_SSHOPTS \
rpi-4 \
'mkdir -p /tmp/board_lock && flock /tmp/board_lock/zc706-1 -c "echo Ok; cat"' \
| (
# End remote flock via FIFO
atexit_unlock() {
echo > $LOCKCTL/lockctl
}
trap atexit_unlock EXIT
# Read "Ok" line when remote successfully locked
read LOCK_OK
echo Power cycling board...
(echo b; sleep 5; echo B; sleep 5) | nc -N -w6 192.168.1.31 3131
echo Power cycle done.
export USER=hydra
export OPENOCD_ZYNQ=${zynq-rs}/openocd
export SZL=${zynqpkgs.szl}
bash ${self}/remote_run.sh -h rpi-4 -o "$NIX_SSHOPTS" -d ${board-package}
echo Waiting for the firmware to boot...
sleep 15
echo Running test kernel...
artiq_run --device-db ${self}/${ddb_folder}/device_db.py ${self}/examples/mandelbrot.py
echo Running ARTIQ unit tests...
export ARTIQ_ROOT=${self}/${ddb_folder}
export ARTIQ_LOW_LATENCY=1
python -m unittest discover artiq.test.coredevice -v
touch $out
echo Completed
(echo b; sleep 5) | nc -N -w6 192.168.1.31 3131
echo Board powered off
)
'';
};
zc706-hitl-tests = make-zc706-hitl-tests { name = "nist_qc2"; board-package = zc706-nist_qc2.zc706-nist_qc2-jtag; };
zc706-acpki-hitl-tests = make-zc706-hitl-tests {
name = "acpki_nist_qc2";
board-package = zc706-acpki_nist_qc2.zc706-acpki_nist_qc2-jtag;
ddb_folder = "examples/acpki";
};
in rec {
packages.x86_64-linux =
{
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
}
// (board-package-set {
target = "zc706";
variant = "cxp_4r_fmc";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock_master";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock_master_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock_satellite";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock_satellite_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2_master";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2_master_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2_satellite";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2_satellite_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock_master";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock_master_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock_satellite";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock_satellite_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2_master";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2_master_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2_satellite";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2_satellite_100mhz";
})
// (board-package-set {
target = "kasli_soc";
variant = "demo";
json = ./demo.json;
})
// (board-package-set {
target = "kasli_soc";
variant = "master";
json = ./kasli-soc-master.json;
})
// (board-package-set {
target = "kasli_soc";
variant = "satellite";
json = ./kasli-soc-satellite.json;
})
// (board-package-set {
target = "ebaz4205";
variant = "base";
});
hydraJobs =
packages.x86_64-linux
// {
inherit zc706-hitl-tests;
inherit zc706-acpki-hitl-tests;
inherit gateware-sim;
inherit fmt-check;
};
formatter.x86_64-linux = pkgs.alejandra;
devShell.x86_64-linux = pkgs.mkShell {
name = "artiq-zynq-dev-shell";
buildInputs = with pkgs; [
rust
llvmPackages_20.llvm
llvmPackages_20.clang-unwrapped
gnumake
cacert
zynqpkgs.mkbootimage
openocd
openssh
rsync
(python3.withPackages (ps: (with artiqpkgs; [migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi])))
artiqpkgs.artiq
artiqpkgs.vivado
binutils-arm
pre-commit
];
ZYNQ_REV = "${zynqRev}";
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include";
ZYNQ_RS = "${zynq-rs}";
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
SZL = "${zynqpkgs.szl}";
};
makeArtiqZynqPackage = board-package-set;
};
}