diff --git a/Scripts/pcie40_program b/Scripts/pcie40_program
new file mode 100755
index 0000000000000000000000000000000000000000..195ff5afc0e21d40875be1180e0c2f2e2ef760da
--- /dev/null
+++ b/Scripts/pcie40_program
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+#ug`pcie40_pgm.description`
+# This simple tool just serves as a shortcut to the ``quartus_pgm`` command. It is preconfigured with the default JTAG chain definition used in a PCIe40 readout board. _
+# NOTE: Programming .rbf files is not yet supported.
+
+JTAG_CABLE=1
+
+#ug`pcie40_pgm.synopsis`
+# *pcie40_pgm* [-c _jtagcable_] _file.sof_|_file.pof_
+
+function usage {
+  echo "pcie40_pgm [-c jtagcable] file.sof|file.pof" >&2
+}
+
+while getopts ":c:h" opt; do
+  case $opt in
+
+#ug`pcie40_pgm.options`jtagcable
+# *-c* _jtagcable_::
+# Use given JTAG cable interface. _jtagcable_ is an integer as printed by ``quartus_pgm -l``. The default value is 1.
+    c) JTAG_CABLE=${OPTARG}
+      ;;
+    h)
+      usage
+      exit 1
+      ;;
+    \?)
+      echo "Invalid option: -${OPTARG}" >&2
+      exit 1
+      ;;
+    :)
+      echo "Option -${OPTARG} requires an argument" >&2
+      exit 1
+      ;;
+  esac
+done
+
+# Discard options
+shift $(($OPTIND - 1))
+
+if [ -z "$1" ]; then
+  usage
+  exit 1
+fi
+IMAGE_PATH=$1
+
+if [ ! -e ${IMAGE_PATH} ]; then
+  echo "File does not exist: ${IMAGE_PATH}" >&2
+  exit 1
+fi
+
+tmpcdf=`mktemp -t pcie40_pgm.XXXXXX.cdf`
+
+IMAGE_DIRNAME=`dirname "${IMAGE_PATH}"`/
+IMAGE_BASENAME=`basename "${IMAGE_PATH}"`
+
+case "${IMAGE_BASENAME##*.}" in
+
+#ug`pcie40_pgm.options`sof
+# _ _file.sof_::
+# The SRAM Object File file to program on the PCIe40 FPGA. _
+sof)
+  cat << EOF > $tmpcdf
+JedecChain;
+	FileRevision(JESD32A);
+	DefaultMfr(6E);
+
+	P ActionCode(Cfg)
+		Device PartName(10AX115S4F45) Path("${IMAGE_DIRNAME}") File("${IMAGE_BASENAME}") MfrSpec(OpMask(1));
+	P ActionCode(Ign)
+		Device PartName(5M2210Z) MfrSpec(OpMask(0) SEC_Device(CFI_1GB) Child_OpMask(1 0));
+
+ChainEnd;
+
+AlteraBegin;
+	ChainType(JTAG);
+AlteraEnd;
+EOF
+  ;;
+#ug`pcie40_pgm.options`pof
+# _ _file.pof_::
+# The Programmer Object File file to store on the PCIe40 flash memory. _
+pof)
+  cat << EOF > $tmpcdf
+JedecChain;
+	FileRevision(JESD32A);
+	DefaultMfr(6E);
+
+	P ActionCode(Ign)
+		Device PartName(10AX115S4F45) MfrSpec(OpMask(0));
+	P ActionCode(Ign)
+		Device PartName(5M2210Z) MfrSpec(OpMask(0) SEC_Device(CFI_1GB) Child_OpMask(3 1 1 1) PFLPath("${IMAGE_PATH}"))
+
+ChainEnd;
+
+AlteraBegin;
+	ChainType(JTAG);
+AlteraEnd;
+EOF
+  ;;
+rbf)
+  >&2 echo ".rbf files are not yet supported"
+  exit 1
+  ;;
+*)
+  >&2 echo "Unknown file type: ${IMAGE_BASENAME}"
+  exit 1
+  ;;
+esac
+
+#cat $tmpcdf
+
+#ug`pcie40_pgm.env`
+# *QUARTUS_ROOTDIR*::
+# The path to the Quartus installation to use. If defined, the programmer binary must be located at ``${QUARTUS_ROOTDIR}/bin/quartus_pgm``.
+
+QUARTUS_PGM=quartus_pgm
+if [ ! -z "${QUARTUS_ROOTDIR}" ]; then
+  QUARTUS_PGM=${QUARTUS_ROOTDIR}/bin/quartus_pgm
+fi
+
+${QUARTUS_PGM} -c ${JTAG_CABLE} $tmpcdf
+
+pgm_result=$?
+
+rm $tmpcdf
+
+#ug`pcie40_pgm.exit`
+# After programming, the tool simply returns the exit status produced by the internal call to the ``quartus_pgm`` command.
+exit $pgm_result