~ruther/nix-fpga

657f7298a01b67041204aea5496e1947a76e64c7 — Rutherther 1 year, 12 days ago 2042c91
feat: add executables to fhs package, split to individual frameworks
28 files changed, 710 insertions(+), 290 deletions(-)

A README.md
M flake.nix
A pkgs/common.nix
A pkgs/final-pkg-generator.nix
A pkgs/intel/quartus/fhs-package.nix
A pkgs/intel/quartus/fhs-shell.nix
A pkgs/intel/quartus/fhs.nix
A pkgs/intel/quartus/udev.nix
A pkgs/questa/fhs-package.nix
A pkgs/questa/fhs-shell.nix
A pkgs/questa/fhs.nix
A pkgs/xilinx/common.nix
A pkgs/xilinx/ise/fhs-package.nix
A pkgs/xilinx/ise/fhs-shell.nix
A pkgs/xilinx/ise/fhs.nix
A pkgs/xilinx/ise/fw.nix
R xilinx/ise/fw/xusb_emb.hex => pkgs/xilinx/ise/fw/xusb_emb.hex
R xilinx/ise/fw/xusb_xlp.hex => pkgs/xilinx/ise/fw/xusb_xlp.hex
R xilinx/ise/fw/xusb_xp2.hex => pkgs/xilinx/ise/fw/xusb_xp2.hex
R xilinx/ise/fw/xusb_xpr.hex => pkgs/xilinx/ise/fw/xusb_xpr.hex
R xilinx/ise/fw/xusb_xse.hex => pkgs/xilinx/ise/fw/xusb_xse.hex
R xilinx/ise/fw/xusb_xup.hex => pkgs/xilinx/ise/fw/xusb_xup.hex
R xilinx/ise/fw/xusbdfwu.hex => pkgs/xilinx/ise/fw/xusbdfwu.hex
A pkgs/xilinx/ise/udev.nix
A pkgs/xilinx/vivado/fhs-package.nix
A pkgs/xilinx/vivado/fhs-shell.nix
A pkgs/xilinx/vivado/fhs.nix
A pkgs/xilinx/vivado/udev.nix
A README.md => README.md +109 -0
@@ 0,0 1,109 @@
# FPGA, ASIC tools on Nix

This repository is inspired by how [nix-matlab](https://gitlab.com/doronbehar/nix-matlab) works.
Most packages here are not kept in the Nix store. They are instead installed somewhere else,
and the packages here are capable of calling the target executables in FHS environment.

## Available packages
Currently supporting: ISE, Vivado, Quartus, Questa.
- ISE
- Vivado
- Quartus
- QuestaSim / ModelSim

## Installing software
To install any of the available software, you will first want to run the installer
of the software in its fhs shell environment. These are called `{sw}-shell`.
For example, to install Quartus, you would do
``` sh
nix run github:Rutherther/nix-fpga#quartus-shell
```
Then go about the installation manually and install wherever.

After the installation, it's important to configure where is Quartus installed. The
FHS scripts are sourcing `~/.config/quartus/nix.sh` file, and assuming `INSTALL_DIR` is
the location of the installation. Specify the whole path including the folder with version
of the software, ie.
``` sh
INSTALL_DIR=/opt/IntelFPGA/quartus/23.1std_lite
```

## Running software
You can either run the software manually from the shell, or run the
package version that starts the main program of the toolchain.

Ie. to run quartus, you would do `nix run github:Rutherther/nix-fpga#quartus`.
To run the shell, you would follow what was done for the installation,
`nix run github:Rutherther/nix-fpga#quartus-shell`. All vendor scripts will be
sourced, bins added to `$PATH`, so the software may be ran directly.

## Udev rules
If you want to flash the FPGA, you will need udev rules installed.
These cannot be installed the same way as on other Linux systems via
vendor's installation scripts. Instead, udev rules are copied to this repository,
and made available via `{sw}-udev-rules`. For example `quartus-udev-rules`.
These have to be put into `services.udev.packages` of your NixOS configuration
to make connection with board possible.

## Licensing
To provide the correct license to the software,
I suggest using the configuration script. This script is
sourced, so you can just put in `export LM_LICENSE_FILE` line
that will set path to the license

## Software specifics
How the configuration should look like, what
options can be used etc.

### Quartus
I was not able to test the udev rules for quartus as I do not have
Intel board on hand.

``` sh
> cat ~/.config/quartus/nix.sh
INSTALL_DIR=/opt/IntelFPGA/quartus/23.1std_lite
```


### Questa
The Questa package allows to add dummy network interface. This allows
license for any interface to work fine. It also bypasses the network
check that has to be performed normally. To enable this bypass, override
the package like so:

``` nix
quartus.override {
    licenseInterface = "AA:BB:CC:DD:EE:FF"; # put interface from the license instead.
};
```

Alternatively you can set this `licenseInterface` to `true`, and configure via `$LICENSE_INTERFACE`
variable declared inside of the `nix.sh` configuration file.

This will also mean internet cannot be used inside of Questa, but to my knowledge
it doesn't use internet in normal usage at all.

``` sh
> cat ~/.config/questa/nix.sh
INSTALL_DIR=/opt/IntelFPGA/quartus/23.1std_lite/questa_fse
LICENSE_INTERFACE=AA:BB:CC:DD:EE:FF # Do not forget to override with `licenseInterface = true;`
export LM_LICENSE_FILE=/path/to/my/license.dat
```

### ISE
I was not able to get the Platform Cable working with ISE. I ended up
going into Vivado, where it seems even older models can be flashed.
So I do synthesis, routing, bitfile generation in ISE, and then flash
via Vivado.

``` sh
> cat ~/.config/ise/nix.sh
INSTALL_DIR=/opt/Xilinx/ISE/14.7/ISE_DS
```

### Vivado

``` sh
> cat ~/.config/vivado/nix.sh
INSTALL_DIR=/opt/Xilinx/Vivado/2023.1
```

M flake.nix => flake.nix +41 -290
@@ 8,305 8,56 @@
      pkgs = import nixpkgs {
        inherit system;
      };
      runScriptPrefix = package: required: ''
        # Search for an imperative declaration of the installation directory of ${package}
        error=0
        if [[ -f ~/.config/${package}/nix.sh ]]; then
          source ~/.config/${package}/nix.sh
        else
          echo "nix-${package}-error: Did not find ~/.config/${package}/nix.sh" >&2
          error=1
        fi
        if [[ ! -d "$INSTALL_DIR" ]]; then
          echo "nix-${package}-error: INSTALL_DIR $INSTALL_DIR isn't a directory" >&2
          error=2
      '' + ''
        fi

        if [[ $error -ne 0 ]]; then
          exit $error
        fi
      '';
      myLib = import ./pkgs/common.nix { inherit pkgs; };

      # pkgs for Xilinx tools
      xilinxTargetPkgs = pkgs: with pkgs; [
        gnumake
        coreutils
        stdenv.cc.cc
        ncurses5
        ncurses
        zlib
        xorg.libX11
        xorg.libXrender
        xorg.libxcb
        xorg.libXext
        xorg.libXtst
        xorg.libXi
        freetype
        gtk2
        glib
        libxcrypt-legacy
        gperftools
        glibc.dev
        fontconfig
        liberation_ttf

        # Xilinx ISE
        glib
        iproute2
        libstdcxx5
        libusb-compat-0_1
        libuuid
        motif
        # motif3-compat
        xorg.libXcursor
        xorg.libXft
        xorg.libXmu
        xorg.libXp
        xorg.libXt
        xorg.libXrandr
        xorg.libSM
        xorg.libICE
      ];

      diamondTargetPkgs = pkgs: with pkgs; [
        fontconfig
        libgcc
        glibc
        stdenv.cc.cc.lib
        xorg.libXext
        xorg.libXft
        xorg.libX11
        xorg.libXrender
      ];

      quartusTargetPkgs = pkgs: with pkgs; [
        stdenv.cc.cc.lib
        zlib
        glib
        libxcrypt-legacy
        libpng12
        freetype
        fontconfig.lib
        xorg.libSM
        xorg.libICE
        xorg.libXrender
        xorg.libXext
        xorg.libX11
        xorg.libXtst
        xorg.libXi
        xorg.libXft
        xorg.xcbutil
        xorg.libxcb.out
        xorg.xcbutilrenderutil.out
        xorg.libXau
        xorg.libXdmcp
        qt6.qtwayland
        libsForQt5.qt5.qtwayland
        gtk2
        libelf
        expat
        dbus.lib
        brotli.lib
        libpng
        bzip2.out
      ];

      questaFhsEnv = pkgs.buildFHSEnv {
        targetPkgs = quartusTargetPkgs;
        name = "questasim-env";
        runScript = pkgs.writeScript "questasim-env" ''
          #!/usr/bin/env bash
          ${runScriptPrefix "questa" true}
          if [[ ! -z $INSTALL_DIR ]]; then
            export PATH=$INSTALL_DIR/bin:$PATH
          fi
          export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
          exec "$@"
        '';
      };

      questaFiles = [
        "crd2bin" "dumplog64" "flps_util" "hdloffice" "hm_entity" "jobspy" "mc2com"
        "mc2perfanalyze" "mc2_util" "qhcvt" "qhdel" "qhdir" "qhgencomp" "qhlib" "qhmake" "qhmap"
        "qhsim" "qrun" "qverilog" "qvhcom" "qvlcom" "qwave2vcd" "qwaveman" "qwaveutils"
        "sccom" "scgenmod" "sdfcom" "sm_entity" "triage" "vcd2qwave" "vcd2wlf" "vcom" "vcover"
        "vdbg" "vdel" "vdir" "vencrypt" "verror" "vgencomp" "vhencrypt" "vis" "visualizer"
        "vlib" "vlog" "vmake" "vmap" "vopt" "vovl" "vrun"
        "vsim" "wlf2log" "wlf2vcd" "wlfman" "wlfrecover" "xml2ucdb"
      ];

      wrappedQuestaScripts = map (x: pkgs.writeScriptBin x ''
        #!/usr/bin/env bash
        exec ${questaFhsEnv}/bin/questasim-env ${x} "$@"
      '') questaFiles;
      # diamondTargetPkgs = pkgs: with pkgs; [
      #   fontconfig
      #   libgcc
      #   glibc
      #   stdenv.cc.cc.lib
      #   xorg.libXext
      #   xorg.libXft
      #   xorg.libX11
      #   xorg.libXrender
      # ];

    in {
      packages.${system} = {
        diamond-shell = pkgs.buildFHSEnv {
          multiPkgs = diamondTargetPkgs;
          name = "diamond-shell";
          multiArch = true;
          runScript = pkgs.writeScript "diamond-shell" ''
            export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
            exec bash
          '';
        };
        quartus-shell = pkgs.buildFHSEnv {
          targetPkgs = quartusTargetPkgs;
          name = "quartus-shell";
          runScript = pkgs.writeScript "quartus-shell" ''
            ${runScriptPrefix "quartus" false}
            if [[ ! -z $INSTALL_DIR ]]; then
              export PATH=$INSTALL_DIR/quartus/bin:$INSTALL_DIR/questa_fse/bin:$PATH
            fi
            export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
            exec bash
          '';
        };

        quartus = pkgs.buildFHSEnv {
          targetPkgs = quartusTargetPkgs;
          name = "quartus";
          runScript = pkgs.writeScript "quartus" ''
            ${runScriptPrefix "quartus" true}
            export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
            exec $INSTALL_DIR/quartus/bin/quartus
          '';
        };

        questa = pkgs.buildEnv {
          name = "questa";
          paths = wrappedQuestaScripts ++ [
            (pkgs.writeTextFile {
              name = "modelsim.ini";
              text = ''
                Dummy ini
                # For VUnit to find ModelSim.
              '';
              destination = "/modelsim.ini";
            })
          ];

          meta = {
            description = "Environment containing QuestaSim/ModelSim executable files.";
            mainProgram = "vsim";
          };
        };

        quartus-udev-rules = pkgs.writeTextFile {
          name = "quartus-usbblaster";
          destination = "/etc/udev/rules.d/51-usbblaster.rules";
          text = ''
            # Intel FPGA Download Cable
            SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6001", MODE="0666"
            SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6002", MODE="0666"
            SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6003", MODE="0666"

            # Intel FPGA Download Cable II
            SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6010", MODE="0666"
            SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6810", MODE="0666"
          '';
        };

        vivado-shell = pkgs.buildFHSEnv {
          targetPkgs = xilinxTargetPkgs;

          name = "vivado-shell";
          runScript = pkgs.writeScript "vivado-shell" ''
            ${runScriptPrefix "ise" false}
            if [[ ! -z $INSTALL_DIR ]]; then
              source $INSTALL_DIR/Vivado/2023.1/settings64.sh
            fi
            export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
            exec bash
          '';
        };
        vivado = pkgs.buildFHSEnv {
          targetPkgs = xilinxTargetPkgs;

          name = "vivado-runner";
          runScript = pkgs.writeScript "vivado-runner" ''
            ${runScriptPrefix "vivado" true}
            export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
            exec $INSTALL_DIR/Vivado/2023.1/bin/vivado "$@"
          '';
        };

        ise-shell = pkgs.buildFHSEnv {
          targetPkgs = pkgs: xilinxTargetPkgs pkgs ++ [
            self.packages.${system}.ise-fw
          ];

          name = "ise-shell";
          runScript = pkgs.writeScript "ise-shell" ''
            ${runScriptPrefix "ise" false}
            if [[ ! -z $INSTALL_DIR ]]; then
              source $INSTALL_DIR/14.7/ISE_DS/settings64.sh $INSTALL_DIR/14.7/ISE_DS
            fi
            exec bash
          '';
        };

        ise = pkgs.buildFHSEnv {
          targetPkgs = xilinxTargetPkgs;
          name = "xilinx-runner";

          runScript = ''
            ${runScriptPrefix "ise" true}
            source $INSTALL_DIR/14.7/ISE_DS/settings64.sh $INSTALL_DIR/14.7/ISE_DS
            $INSTALL_DIR/14.7/ISE_DS/ISE/bin/lin64/ise
          '';
        # diamond-shell = pkgs.buildFHSEnv {
        #   multiPkgs = diamondTargetPkgs;
        #   name = "diamond-shell";
        #   multiArch = true;
        #   runScript = pkgs.writeScript "diamond-shell" ''
        #     export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
        #     exec bash
        #   '';
        # };

        questa-shell = pkgs.callPackage ./pkgs/questa/fhs-shell.nix { inherit myLib; };
        questa = pkgs.callPackage ./pkgs/questa/fhs-package.nix { inherit myLib; };

        quartus-shell = pkgs.callPackage ./pkgs/intel/quartus/fhs-shell.nix { inherit myLib; };
        quartus = pkgs.callPackage ./pkgs/intel/quartus/fhs-package.nix { inherit myLib; };
        quartus-udev-rules = pkgs.callPackage ./pkgs/intel/quartus/udev.nix {};

        vivado-shell = pkgs.callPackage ./pkgs/xilinx/vivado/fhs-shell.nix { inherit myLib; };
        vivado = pkgs.callPackage ./pkgs/xilinx/vivado/fhs-package.nix { inherit myLib; };
        vivado-udev-rules = pkgs.callPackage ./pkgs/xilinx/vivado/udev.nix {};

        ise-shell = pkgs.callPackage ./pkgs/xilinx/ise/fhs-shell.nix {
          inherit myLib;
          ise-fw = self.packages.${system}.ise-fw;
        };

        ise-fw = pkgs.stdenv.mkDerivation {
          name = "xilinx-jtag-fw";
          phases = ["unpackPhase" "installPhase"];
          src = ./xilinx/ise/fw;
          installPhase = ''
            mkdir -p $out/share
            cp * $out/share/
          '';
        ise = pkgs.callPackage ./pkgs/xilinx/ise/fhs-package.nix {
          inherit myLib;
          ise-fw = self.packages.${system}.ise-fw;
        };

        ise-udev-rules = pkgs.writeTextFile (let
        ise-udev-rules = pkgs.callPackage ./pkgs/xilinx/ise/udev.nix {
          inherit myLib;
          ise-fw = self.packages.${system}.ise-fw;
        in {
          name = "ise-udev-rules";
          destination = "/etc/udev/rules.d/05-xilinx-ise.rules";
          text = ''
            # version 0003
            SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0008", MODE="666"
            BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0007", RUN+="${pkgs.fxload} -v -t fx2 -I ${ise-fw}/share/xusbdfwu.hex -D $tempnode"
            BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0009", RUN+="${pkgs.fxload} -v -t fx2 -I ${ise-fw}/share/xusb_xup.hex -D $tempnode"
            BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="000d", RUN+="${pkgs.fxload} -v -t fx2 -I ${ise-fw}/share/xusb_emb.hex -D $tempnode"
            BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="000f", RUN+="${pkgs.fxload} -v -t fx2 -I ${ise-fw}/share/xusb_xlp.hex -D $tempnode"
            BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0013", RUN+="${pkgs.fxload} -v -t fx2 -I ${ise-fw}/share/xusb_xp2.hex -D $tempnode"
            BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0015", RUN+="${pkgs.fxload} -v -t fx2 -I ${ise-fw}/share/xusb_xse.hex -D $tempnode"
          '';
        });

        vivado-udev-rules = pkgs.writeTextFile {
          name = "vivado-udev-rules";
          destination = "/etc/udev/rules.d/10-xilinx-vivado.rules";
          text = ''
            # xilinx-ftdi-usb.rules
            ACTION=="add", ATTR{idVendor}=="0403", ATTR{manufacturer}=="Xilinx", MODE:="666"

            # xilinx-digilent-usb.rules
            ATTR{idVendor}=="1443", MODE:="666"
            ACTION=="add", ATTR{idVendor}=="0403", ATTR{manufacturer}=="Digilent", MODE:="666"

            # xilinx-pcusb.rules
            ATTR{idVendor}=="03fd", ATTR{idProduct}=="0008", MODE="666"
            ATTR{idVendor}=="03fd", ATTR{idProduct}=="0007", MODE="666"
            ATTR{idVendor}=="03fd", ATTR{idProduct}=="0009", MODE="666"
            ATTR{idVendor}=="03fd", ATTR{idProduct}=="000d", MODE="666"
            ATTR{idVendor}=="03fd", ATTR{idProduct}=="000f", MODE="666"
            ATTR{idVendor}=="03fd", ATTR{idProduct}=="0013", MODE="666"
            ATTR{idVendor}=="03fd", ATTR{idProduct}=="0015", MODE="666"
          '';
        };
        ise-fw = pkgs.callPackage ./pkgs/xilinx/ise/fw.nix { inherit myLib; };
      };
    };
}

A pkgs/common.nix => pkgs/common.nix +25 -0
@@ 0,0 1,25 @@
{ pkgs, ... }:

{
  runScriptPrefix = package: required: ''
    # Search for an imperative declaration of the installation directory of ${package}
    error=0
    if [[ -f ~/.config/${package}/nix.sh ]]; then
      source ~/.config/${package}/nix.sh
    else
      echo "nix-${package}-error: Did not find ~/.config/${package}/nix.sh" >&2
      error=1
    fi
    if [[ ! -d "$INSTALL_DIR" ]]; then
      echo "nix-${package}-error: INSTALL_DIR $INSTALL_DIR isn't a directory" >&2
      error=2
  '' + ''
    fi

    if [[ $error -ne 0 ]]; then
      exit $error
    fi
  '';

  finalPkgGenerator = pkgs.callPackage ./final-pkg-generator.nix {};
}

A pkgs/final-pkg-generator.nix => pkgs/final-pkg-generator.nix +28 -0
@@ 0,0 1,28 @@
{ lib, stdenv, customInstallScript ? "", fhsEnv ? "", executables ? "", mainProgram ? "" }:

let
  genScript = file: ''
    #!/usr/bin/env bash
    exec ${lib.getExe fhsEnv} ${file} \"\$@\"
  '';

  createScript = file: ''
   echo "${genScript file}" > $out/bin/${file}
   chmod +x $out/bin/${file}
  '';

  createScripts = map (file: createScript file) executables;

in stdenv.mkDerivation {
  name = mainProgram;

  installPhase = ''
    mkdir -p $out/bin
  '' + customInstallScript + (lib.concatStrings createScripts);

  phases = [ "installPhase" ];

  meta = {
    inherit mainProgram;
  };
}

A pkgs/intel/quartus/fhs-package.nix => pkgs/intel/quartus/fhs-package.nix +81 -0
@@ 0,0 1,81 @@
{ pkgs, myLib }:

myLib.finalPkgGenerator.override {
  mainProgram = "quartus";

  fhsEnv = pkgs.callPackage ./fhs.nix {  inherit myLib; };

  executables = [
    "clearbox"
    "dmf_ver"
    "jtagconfig"
    "jtagd"
    "jtagquery"
    "juart-terminal"
    "mega_alt_fault_injection"
    "mega_symc"
    "mega_symcng"
    "mif2hex"
    "mw-regenerate"
    "nios2-flash-programmer"
    "nios2-gdb-server"
    "nios2-terminal"
    "openocd"
    "openocd-cfg-gen"
    "pll_cmd"
    "qatc"
    "qbnl"
    "qcmd"
    "qcrypt"
    "qemit"
    "qeslc"
    "qfid"
    "qmegawiz"
    "qmegawizq"
    "qnsm"
    "qnui"
    "qpgmt"
    "qppl"
    "qred"
    "qreg"
    "qsme"
    "quartus"
    "quartus_asm"
    "quartus_cdb"
    "quartus_cmd"
    "quartus_cpf"
    "quartus_drc"
    "quartus_dse"
    "quartus_dsew"
    "quartus_eda"
    "quartus_fid"
    "quartus_fif"
    "quartus_fit"
    "quartus_hps"
    "quartus-ip-catalog"
    "quartus_jbcc"
    "quartus_jli"
    "quartus_map"
    "quartus_npp"
    "quartus_pgm"
    "quartus_pgmw"
    "quartus_pow"
    "quartus_py"
    "quartus_sh"
    "quartus_si"
    "quartus_sim"
    "quartus_sta"
    "quartus_staw"
    "quartus_stp"
    "quartus_stp_tcl"
    "quartus_stpw"
    "quartus_syn"
    "quartus_template"
    "quartus_worker"
    "qwed"
    "tclsh"
    "uniphy_mcc"
    "wish"
    "xcvr_diffmifgen"
  ];
}

A pkgs/intel/quartus/fhs-shell.nix => pkgs/intel/quartus/fhs-shell.nix +7 -0
@@ 0,0 1,7 @@
{ pkgs, lib, myLib }:

let
  fhs = pkgs.callPackage ./fhs.nix {  inherit myLib; };
in pkgs.writeShellScriptBin "quartus-shell" ''
  exec ${lib.getExe fhs} bash "$@"
''

A pkgs/intel/quartus/fhs.nix => pkgs/intel/quartus/fhs.nix +50 -0
@@ 0,0 1,50 @@
{pkgs, lib, myLib }:

pkgs.buildFHSEnv {
  targetPkgs =
  pkgs: with pkgs; [
    stdenv.cc.cc.lib
    zlib
    glib
    libxcrypt-legacy
    libpng12
    freetype
    fontconfig.lib
    xorg.libSM
    xorg.libICE
    xorg.libXrender
    xorg.libXext
    xorg.libX11
    xorg.libXtst
    xorg.libXi
    xorg.libXft
    xorg.xcbutil
    xorg.libxcb.out
    xorg.xcbutilrenderutil.out
    xorg.libXau
    xorg.libXdmcp
    qt6.qtwayland
    libsForQt5.qt5.qtwayland
    gtk2
    libelf
    expat
    dbus.lib
    brotli.lib
    libpng
    bzip2.out
  ];

  name = "quartus";

  runScript = pkgs.writeScript "questasim-env" ''
    #!/usr/bin/env bash
    ${myLib.runScriptPrefix "quartus" true}
    if [[ ! -z $INSTALL_DIR ]]; then
      export PATH=$INSTALL_DIR/quartus/bin:$PATH
    fi
    export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
    exec "$@"
  '';

  meta.mainProgram = "quartus";
}

A pkgs/intel/quartus/udev.nix => pkgs/intel/quartus/udev.nix +16 -0
@@ 0,0 1,16 @@
{ pkgs, ... }:

pkgs.writeTextFile {
  name = "quartus-usbblaster";
  destination = "/etc/udev/rules.d/51-usbblaster.rules";
  text = ''
    # Intel FPGA Download Cable
    SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6001", MODE="0666"
    SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6002", MODE="0666"
    SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6003", MODE="0666"

    # Intel FPGA Download Cable II
    SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6010", MODE="0666"
    SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6810", MODE="0666"
  '';
}

A pkgs/questa/fhs-package.nix => pkgs/questa/fhs-package.nix +28 -0
@@ 0,0 1,28 @@
{ pkgs, myLib, licenseInterface ? "" }:

myLib.finalPkgGenerator.override {
  mainProgram = "vsim";

  fhsEnv = pkgs.callPackage ./fhs.nix {  inherit myLib licenseInterface; };

  executables = [
    "crd2bin" "dumplog64" "flps_util" "hdloffice" "hm_entity" "jobspy" "mc2com"
    "mc2perfanalyze" "mc2_util" "qhcvt" "qhdel" "qhdir" "qhgencomp" "qhlib" "qhmake" "qhmap"
    "qhsim" "qrun" "qverilog" "qvhcom" "qvlcom" "qwave2vcd" "qwaveman" "qwaveutils"
    "sccom" "scgenmod" "sdfcom" "sm_entity" "triage" "vcd2qwave" "vcd2wlf" "vcom" "vcover"
    "vdbg" "vdel" "vdir" "vencrypt" "verror" "vgencomp" "vhencrypt" "vis" "visualizer"
    "vlib" "vlog" "vmake" "vmap" "vopt" "vovl" "vrun"
    "vsim" "wlf2log" "wlf2vcd" "wlfman" "wlfrecover" "xml2ucdb"
  ];

  # This is here for compatibility with some tools like
  # VUnit, where modelsim.ini is checked to see if the
  # given path is ModelSim installation.
  customInstallScript = ''
    echo -e " \
    ; This is here for compatibility with some tools like\n \
    ; VUnit, where modelsim.ini is checked in modelsim/bin/.. to see if the\n \
    ; given path is ModelSim installation. \
    " > "$out/modelsim.ini"
  '';
}

A pkgs/questa/fhs-shell.nix => pkgs/questa/fhs-shell.nix +7 -0
@@ 0,0 1,7 @@
{ pkgs, lib, myLib, licenseInterface ? "" }:

let
  fhs = pkgs.callPackage ./fhs.nix {  inherit myLib licenseInterface; };
in pkgs.writeShellScriptBin "questa-shell" ''
  exec ${lib.getExe fhs} bash "$@"
''

A pkgs/questa/fhs.nix => pkgs/questa/fhs.nix +77 -0
@@ 0,0 1,77 @@
{pkgs, lib, myLib, licenseInterface ? "" }:

let
  bypassNetwork = licenseInterface == true || (licenseInterface != "");
  imperativeInterface = licenseInterface == true;
  declarativeInterface = bypassNetwork && !imperativeInterface;
in pkgs.buildFHSEnv {
  targetPkgs =
  pkgs: with pkgs; [
    stdenv.cc.cc.lib
    zlib
    glib
    libxcrypt-legacy
    libpng12
    freetype
    fontconfig.lib
    xorg.libSM
    xorg.libICE
    xorg.libXrender
    xorg.libXext
    xorg.libX11
    xorg.libXtst
    xorg.libXi
    xorg.libXft
    xorg.xcbutil
    xorg.libxcb.out
    xorg.xcbutilrenderutil.out
    xorg.libXau
    xorg.libXdmcp
    qt6.qtwayland
    libsForQt5.qt5.qtwayland
    gtk2
    libelf
    expat
    dbus.lib
    brotli.lib
    libpng
    bzip2.out
  ];

  name = "questasim";

  unshareNet = bypassNetwork;

  extraBwrapArgs = lib.lists.optionals bypassNetwork [
    "--cap-add CAP_NET_ADMIN"
  ];

  runScript = ''
    #!/usr/bin/env bash
    ${myLib.runScriptPrefix "questa" true}
    if [[ ! -z $INSTALL_DIR ]]; then
      export PATH=$INSTALL_DIR/bin:$PATH
    fi
    export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
    '' +

    (lib.optionalString imperativeInterface ''
      if [[ -z $LICENSE_INTERFACE ]]; then
        echo "nix-questa-error: LICENSE_INTERFACE is not set, but imperative license interface setup has been chosen. Continuing, but expect issues with license."
      else
        ip link add eth0 type dummy
        ip link set dev eth0 address $LICENSE_INTERFACE
      fi
    '') +

    (lib.optionalString declarativeInterface ''
      ip link add eth0 type dummy
      ip link set dev eth0 address ${licenseInterface}
    # # # '') +

    ''
      exec "$@"
    '';

  meta.mainProgram = "questasim";
}

A pkgs/xilinx/common.nix => pkgs/xilinx/common.nix +41 -0
@@ 0,0 1,41 @@
{
  targetPkgs = pkgs: with pkgs; [
    gnumake
    coreutils
    stdenv.cc.cc
    ncurses5
    ncurses
    zlib
    xorg.libX11
    xorg.libXrender
    xorg.libxcb
    xorg.libXext
    xorg.libXtst
    xorg.libXi
    freetype
    gtk2
    glib
    libxcrypt-legacy
    gperftools
    glibc.dev
    fontconfig
    liberation_ttf

    # Xilinx ISE
    glib
    iproute2
    libstdcxx5
    libusb-compat-0_1
    libuuid
    motif
    # motif3-compat
    xorg.libXcursor
    xorg.libXft
    xorg.libXmu
    xorg.libXp
    xorg.libXt
    xorg.libXrandr
    xorg.libSM
    xorg.libICE
  ];
}

A pkgs/xilinx/ise/fhs-package.nix => pkgs/xilinx/ise/fhs-package.nix +14 -0
@@ 0,0 1,14 @@
{ pkgs, myLib, ise-fw, ... }:

myLib.finalPkgGenerator.override {
  mainProgram = "ise";

  fhsEnv = pkgs.callPackage ./fhs.nix {  inherit myLib ise-fw; };

  executables = [
    # TODO
    "ise"
    "xflow"
    "impact"
  ];
}

A pkgs/xilinx/ise/fhs-shell.nix => pkgs/xilinx/ise/fhs-shell.nix +7 -0
@@ 0,0 1,7 @@
{ pkgs, lib, myLib, ise-fw, ... }:

let
  fhs = pkgs.callPackage ./fhs.nix {  inherit myLib ise-fw; };
in pkgs.writeShellScriptBin "ise-shell" ''
  exec ${lib.getExe fhs} bash "$@"
''

A pkgs/xilinx/ise/fhs.nix => pkgs/xilinx/ise/fhs.nix +20 -0
@@ 0,0 1,20 @@
{ pkgs, myLib, ise-fw, ... }:

pkgs.buildFHSEnv {
  targetPkgs = pkgs: ((import ../common.nix).targetPkgs pkgs) ++ [
    ise-fw
  ];

  name = "ise";

  runScript = ''
    ${myLib.runScriptPrefix "ise" false}
    if [[ ! -z $INSTALL_DIR ]]; then
      source $INSTALL_DIR/settings64.sh "$INSTALL_DIR"
    fi
    export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
    exec "$@"
  '';

  meta.mainProgram = "ise";
}

A pkgs/xilinx/ise/fw.nix => pkgs/xilinx/ise/fw.nix +11 -0
@@ 0,0 1,11 @@
{ pkgs, ... }:

pkgs.stdenv.mkDerivation {
  name = "xilinx-jtag-fw";
  phases = ["unpackPhase" "installPhase"];
  src = ./fw;
  installPhase = ''
    mkdir -p $out/share
    cp * $out/share/
  '';
}

R xilinx/ise/fw/xusb_emb.hex => pkgs/xilinx/ise/fw/xusb_emb.hex +0 -0
R xilinx/ise/fw/xusb_xlp.hex => pkgs/xilinx/ise/fw/xusb_xlp.hex +0 -0
R xilinx/ise/fw/xusb_xp2.hex => pkgs/xilinx/ise/fw/xusb_xp2.hex +0 -0
R xilinx/ise/fw/xusb_xpr.hex => pkgs/xilinx/ise/fw/xusb_xpr.hex +0 -0
R xilinx/ise/fw/xusb_xse.hex => pkgs/xilinx/ise/fw/xusb_xse.hex +0 -0
R xilinx/ise/fw/xusb_xup.hex => pkgs/xilinx/ise/fw/xusb_xup.hex +0 -0
R xilinx/ise/fw/xusbdfwu.hex => pkgs/xilinx/ise/fw/xusbdfwu.hex +0 -0
A pkgs/xilinx/ise/udev.nix => pkgs/xilinx/ise/udev.nix +16 -0
@@ 0,0 1,16 @@
{ pkgs, fxload, ise-fw, ... }:

pkgs.writeTextFile {
  name = "ise-udev-rules";
  destination = "/etc/udev/rules.d/05-xilinx-ise.rules";
  text = ''
    # version 0003
    SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0008", MODE="666"
    BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0007", RUN+="${fxload} -v -t fx2 -I ${ise-fw}/share/xusbdfwu.hex -D $tempnode"
    BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0009", RUN+="${fxload} -v -t fx2 -I ${ise-fw}/share/xusb_xup.hex -D $tempnode"
    BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="000d", RUN+="${fxload} -v -t fx2 -I ${ise-fw}/share/xusb_emb.hex -D $tempnode"
    BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="000f", RUN+="${fxload} -v -t fx2 -I ${ise-fw}/share/xusb_xlp.hex -D $tempnode"
    BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0013", RUN+="${fxload} -v -t fx2 -I ${ise-fw}/share/xusb_xp2.hex -D $tempnode"
    BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0015", RUN+="${fxload} -v -t fx2 -I ${ise-fw}/share/xusb_xse.hex -D $tempnode"
  '';
}

A pkgs/xilinx/vivado/fhs-package.nix => pkgs/xilinx/vivado/fhs-package.nix +84 -0
@@ 0,0 1,84 @@
{ pkgs, myLib }:

myLib.finalPkgGenerator.override {
  mainProgram = "vivado";

  fhsEnv = pkgs.callPackage ./fhs.nix {  inherit myLib; };

  executables = [
    # From Vivado bin folder
    "bootgen"
    "cdoutil"
    "cdoutil_int"
    "combine_dfx_bitstreams"
    "cs_server"
    "diffbd"
    "hw_server"
    "hw_serverpv"
    "ldlibpath.sh"
    "loader"
    "manage_ipcache"
    "program_ftdi"
    "rdiArgs.sh"
    "setEnvAndRunCmd.sh"
    "setupEnv.sh"
    "stapl_player"
    "svf_utility"
    "symbol_server"
    "tcflog"
    "unsetldlibpath.sh"
    "unwrapped"
    "updatemem"
    "vivado"
    "vlm"
    "wbtcv"
    "xar"
    "xcd"
    "xcrg"
    "xelab"
    "xlicdiag"
    "xrcserver"
    "xrt_server"
    "xsc"
    "xsdb"
    "xsim"
    "xtclsh"
    "xvc_pcie"
    "xvhdl"
    "xvlog"

    # From Vitis bin folder
    "apcc"
    "hlsArgs.sh"
    "ldlibpath.sh"
    "loader"
    "rdiArgs.sh"
    "setEnvAndRunCmd.sh"
    "setupEnv.sh"
    "unsetldlibpath.sh"
    "unwrapped"
    "vitis_hls"
    "xlicdiag"

    # From ModelComposer bin folder
    "ldlibpath.sh"
    "loader"
    "model_composer"
    "modelcomposerArgs.sh"
    "rdiArgs.sh"
    "setEnvAndRunCmd.sh"
    "setPatchEnv.sh"
    "setupEnv.sh"
    "unsetldlibpath.sh"
    "unwrapped"

    # From DocNav bin folder
    "AppRun"
    "docnav"
    "lib"
    "libexec"
    "pdfjs"
    "plugins"
    "translations"
  ];
}

A pkgs/xilinx/vivado/fhs-shell.nix => pkgs/xilinx/vivado/fhs-shell.nix +7 -0
@@ 0,0 1,7 @@
{ pkgs, lib, myLib }:

let
  fhs = pkgs.callPackage ./fhs.nix {  inherit myLib; };
in pkgs.writeShellScriptBin "vivado-shell" ''
  exec ${lib.getExe fhs} bash "$@"
''

A pkgs/xilinx/vivado/fhs.nix => pkgs/xilinx/vivado/fhs.nix +18 -0
@@ 0,0 1,18 @@
{ pkgs, myLib }:

pkgs.buildFHSEnv {
  targetPkgs = (import ../common.nix).targetPkgs;

  name = "vivado";

  runScript = ''
    ${myLib.runScriptPrefix "vivado" false}
    if [[ ! -z $INSTALL_DIR ]]; then
      source $INSTALL_DIR/settings64.sh $INSTALL_DIR
    fi
    export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH
    exec "$@"
  '';

  meta.mainProgram = "vivado";
}

A pkgs/xilinx/vivado/udev.nix => pkgs/xilinx/vivado/udev.nix +23 -0
@@ 0,0 1,23 @@
{ pkgs }:

pkgs.writeTextFile {
  name = "vivado-udev-rules";
  destination = "/etc/udev/rules.d/10-xilinx-vivado.rules";
  text = ''
    # xilinx-ftdi-usb.rules
    ACTION=="add", ATTR{idVendor}=="0403", ATTR{manufacturer}=="Xilinx", MODE:="666"

    # xilinx-digilent-usb.rules
    ATTR{idVendor}=="1443", MODE:="666"
    ACTION=="add", ATTR{idVendor}=="0403", ATTR{manufacturer}=="Digilent", MODE:="666"

    # xilinx-pcusb.rules
    ATTR{idVendor}=="03fd", ATTR{idProduct}=="0008", MODE="666"
    ATTR{idVendor}=="03fd", ATTR{idProduct}=="0007", MODE="666"
    ATTR{idVendor}=="03fd", ATTR{idProduct}=="0009", MODE="666"
    ATTR{idVendor}=="03fd", ATTR{idProduct}=="000d", MODE="666"
    ATTR{idVendor}=="03fd", ATTR{idProduct}=="000f", MODE="666"
    ATTR{idVendor}=="03fd", ATTR{idProduct}=="0013", MODE="666"
    ATTR{idVendor}=="03fd", ATTR{idProduct}=="0015", MODE="666"
  '';
}

Do not follow this link