{ pkgs, isePath ? "/opt/Xilinx/14.7/ISE_DS", vivadoPath ? "/opt/Xilinx/Vivado/2022.2" }:
rec {
  ise = let
    makeXilinxEnv = name: pkgs.buildFHSUserEnv {
      inherit name;
      targetPkgs = pkgs: (
        with pkgs; [
          ncurses5
          zlib
          libuuid
          xorg.libSM
          xorg.libICE
          xorg.libXrender
          xorg.libX11
          xorg.libXext
          xorg.libXtst
          xorg.libXi
        ]
      );
      profile = 
        ''
        source ${isePath}/common/.settings64.sh ${isePath}/common
        source ${isePath}/ISE/.settings64.sh ${isePath}/ISE
        '';
      runScript = name;
    };
  in
    pkgs.lib.attrsets.genAttrs ["xst" "ngdbuild" "cpldfit" "taengine" "hprep6"] makeXilinxEnv;
  vivado = pkgs.buildFHSUserEnv {
    name = "vivado";
    targetPkgs = pkgs: (
      with pkgs; let
        # Apply patch from https://github.com/nix-community/nix-environments/pull/54
        # to fix ncurses libtinfo.so's soname issue
        ncurses' = ncurses5.overrideAttrs (old: {
          configureFlags = old.configureFlags ++ [ "--with-termlib" ];
          postFixup = "";
        });
      in [
        libxcrypt-legacy
        (ncurses'.override { unicodeSupport = false; })
        zlib
        libuuid
        xorg.libSM
        xorg.libICE
        xorg.libXrender
        xorg.libX11
        xorg.libXext
        xorg.libXtst
        xorg.libXi
      ]
    );
    profile = "source ${vivadoPath}/settings64.sh";
    runScript = "vivado";
  };
  migen = pkgs.python3Packages.buildPythonPackage {
    pname = "migen";
    version = "unstable-2024-05-02";
    src = pkgs.fetchFromGitHub {
      owner = "m-labs";
      repo = "migen";
      rev = "4790bb577681a8c3a8d226bc196a4e5deb39e4df";
      sha256 = "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=";
    };
    format = "pyproject";
    nativeBuildInputs = [ pkgs.python3Packages.setuptools ];
    propagatedBuildInputs = with pkgs.python3Packages; [ colorama ];
  };
  asyncserial = pkgs.python3Packages.buildPythonPackage {
    pname = "asyncserial";
    version = "0.1";
    src = pkgs.fetchFromGitHub {
      owner = "m-labs";
      repo = "asyncserial";
      rev = "d95bc1d6c791b0e9785935d2f62f628eb5cdf98d";
      sha256 = "0yzkka9jk3612v8gx748x6ziwykq5lr7zmr9wzkcls0v2yilqx9k";
    };
    propagatedBuildInputs = with pkgs.python3Packages; [ pyserial ];
  };
  misoc = pkgs.python3Packages.buildPythonPackage {
    pname = "misoc";
    version = "unstable-2021-10-10";
    src = pkgs.fetchFromGitHub {
      owner = "m-labs";
      repo = "misoc";
      rev = "f5203e406520874e15ab5d070058ef642fc57fd9";
      sha256 = "sha256-/2XTejqj0Bo81HaTrlTSWwInnWwsuqnq+CURXbpIrkA=";
      fetchSubmodules = true;
    };
    # TODO: fix misoc bitrot and re-enable tests
    doCheck = false;
    propagatedBuildInputs = with pkgs.python3Packages; [ pyserial jinja2 numpy asyncserial migen ];
  };
}