let
	mozillaOverlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
	pkgs = import <nixpkgs> {overlays = [mozillaOverlay];};
in with pkgs;
let
	migen			= callPackage ./nix/migen.nix {};
	# nMigen support for DiffPairs and IO_STANDARD="SB_LVDS_INPUT" seems questionable
	nmigen			= callPackage ./nix/nmigen.nix {};
	nmigen-boards	= callPackage ./nix/nmigen-boards.nix { inherit nmigen; };
	openocd			= callPackage ./nix/openocd.nix {};
	rustPlatform	= callPackage ./nix/rustPlatform.nix {};
	itm				= callPackage ./nix/itm.nix {inherit rustPlatform;};

	runOpenOcd = writeShellScriptBin "run-openocd" ''
		openocd \
		-f board/st_nucleo_h743zi.cfg \
		-c init &
		sleep 1
	'';

	runOpenOcdBlock = writeShellScriptBin "run-openocd-block" ''
		openocd -f board/st_nucleo_h743zi.cfg
	'';

	setGDBConfigFile = writeShellScriptBin "set-gdb-config-file" ''
		if [[ $1 == "" ]]
		then
			sed -i "2s/.*/runner = \"gdb -q -x gdb_config\/openocd.gdb\"/" .cargo/config
			echo "GDB config file: openocd.gdb"
		else
			sed -i "2s/.*/runner = \"gdb -q -x gdb_config\/$1.gdb\"/" .cargo/config
			echo "GDB config file: $1.gdb"
		fi
	'';

	runEthernetServer = writeShellScriptBin "run-ethernet-server" ''
		set-gdb-config-file && cargo run --example ethernet
	'';

	editNMigenScript = writeShellScriptBin "edit-nmigen-script" ''
		nano -m nmigen/fpga_config.py
	'';

	compileNMigenScript = writeShellScriptBin "compile-nmigen-script" ''
		python3 nmigen/fpga_config.py
		echo "Compiled fpga_config.py to top.bin"
	'';

	flashFPGAConfig = writeShellScriptBin "flash-fpga-config" ''
		set-gdb-config-file "fpga_config" && cargo run --example fpga_config
	'';

	configureFPGA = writeShellScriptBin "configure-fpga" ''
		nc -zv localhost 3333			\
		&& compile-nmigen-script 		\
		&& flash-fpga-config 			\
		|| echo "Please run OpenOcd first."
	'';

	verifyFPGAConfig = writeShellScriptBin "verify-fpga-config" ''
		gdb -x gdb_config/fpga_verify.gdb
		diff build/top.bin mem.bin
		rm mem.bin
	'';

	resetFlash = writeShellScriptBin "reset-flash" ''
		gdb -batch -x gdb_config/reset.gdb
		echo "Reset is complete, please reset the openocd server."
	'';

in
	stdenv.mkDerivation {
		name = "nix-shell";		
		buildInputs = with rustPlatform.rust; [
			(pkgs.python3.withPackages(ps: [ migen nmigen nmigen-boards]))
			pkgs.yosys
			pkgs.nextpnr
			pkgs.icestorm
			pkgs.gdb
			openocd
			rustc
			cargo
			itm
			runOpenOcd
			runOpenOcdBlock
			setGDBConfigFile
			runEthernetServer
			editNMigenScript
			compileNMigenScript
			flashFPGAConfig
			configureFPGA
			verifyFPGAConfig
			resetFlash
		];

		RUST_BACKTRACE = 1;
	}