Skip to content

Instantly share code, notes, and snippets.

@jwiegley
Created April 2, 2026 20:50
Show Gist options
  • Select an option

  • Save jwiegley/16305d8b247841eae4d0cb6028bfdada to your computer and use it in GitHub Desktop.

Select an option

Save jwiegley/16305d8b247841eae4d0cb6028bfdada to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# update-bitfiles — Update FPGA bitfiles on all BittWare cards via pho
#
# Usage:
# update-bitfiles <path-to-rbf-file>
# update-bitfiles /ice/svt/releases/archer/archer_agm_01.05.06.00_02.24.26/archer_agm_01.05.06.00.rbf
# update-bitfiles -c 5 <path-to-rbf-file> # update only card 5
# update-bitfiles --list-releases # browse available releases on ICE
# update-bitfiles --status # show current card/image status
#
set -euo pipefail
readonly IMAGES_DIR="/opt/positron/images"
readonly ICE_RELEASES="/ice/svt/releases/archer"
readonly SCRIPT_NAME="${0##*/}"
CARD_FLAG=() # empty = all cards; set by -c
# ── Helpers ──────────────────────────────────────────────────────────────────
die() { printf '%s: error: %s\n' "$SCRIPT_NAME" "$*" >&2; exit 1; }
info() { printf '==> %s\n' "$*"; }
warn() { printf '*** %s\n' "$*" >&2; }
usage() {
cat <<'USAGE'
Usage: update-bitfiles [-c <card>] <path-to-rbf-file>
update-bitfiles --status Show current card/image state
update-bitfiles --list-releases List .rbf files available on ICE
Options:
-c <card> Target a specific card by index (default: all cards)
Examples:
update-bitfiles /ice/svt/releases/archer/archer_agm_01.05.06.00_02.24.26/archer_agm_01.05.06.00.rbf
update-bitfiles -c 5 /opt/positron/images/archer_agm_01.05.06.00.rbf
USAGE
}
command_exists() { command -v "$1" &>/dev/null; }
check_prereqs() {
command_exists pho || die "pho is not installed (install platformd to get it)"
}
# ── Status ───────────────────────────────────────────────────────────────────
show_status() {
info "Detected cards:"
pho bw cards list
echo
info "Current active images:"
pho bw images current
echo
info "Images in flash table:"
pho bw images list
}
# ── List available releases on ICE ───────────────────────────────────────────
list_releases() {
if [[ ! -d "$ICE_RELEASES" ]]; then
die "ICE releases directory not found: $ICE_RELEASES (is ICE mounted?)"
fi
info "Available releases in $ICE_RELEASES:"
echo
for dir in "$ICE_RELEASES"/*/; do
[[ -d "$dir" ]] || continue
local rbf
rbf=$(find "$dir" -maxdepth 1 -name '*.rbf' 2>/dev/null | head -n1)
if [[ -n "$rbf" ]]; then
printf ' %s\n' "$rbf"
fi
done
}
# ── Main update flow ─────────────────────────────────────────────────────────
do_update() {
local rbf_source="$1"
# Validate input file
[[ -f "$rbf_source" ]] || die "File not found: $rbf_source"
[[ "$rbf_source" == *.rbf ]] || die "Expected an .rbf file, got: $rbf_source"
local rbf_name
rbf_name="$(basename "$rbf_source")"
local card_label="all cards"
if [[ ${#CARD_FLAG[@]} -gt 0 ]]; then
card_label="card ${CARD_FLAG[1]}"
fi
info "Bitfile update plan:"
echo " Source: $rbf_source"
echo " Image: $rbf_name"
echo " Target: $card_label"
echo " Staging: $IMAGES_DIR/$rbf_name"
echo
# Show current state
info "Current card status:"
pho bw "${CARD_FLAG[@]}" cards list
echo
info "Current active images:"
pho bw "${CARD_FLAG[@]}" images current
echo
# Confirm
[[ -t 0 ]] || die "stdin is not a terminal; cannot prompt for confirmation (use a tty)"
printf 'Proceed with update? [y/N] '
read -r answer
[[ "$answer" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 0; }
echo
# Step 1: Copy .rbf to local images directory
info "Step 1/4: Copying bitfile to $IMAGES_DIR ..."
if [[ ! -d "$IMAGES_DIR" ]]; then
sudo mkdir -p "$IMAGES_DIR" || die "Failed to create $IMAGES_DIR (need sudo?)"
fi
sudo cp -v "$rbf_source" "$IMAGES_DIR/$rbf_name" || die "Failed to copy bitfile to $IMAGES_DIR"
echo
# Step 2: Upload to cards
info "Step 2/4: Uploading image to $card_label (this may take a while) ..."
if [[ ${#CARD_FLAG[@]} -eq 0 ]]; then
warn "Be patient -- uploading to 8 cards takes significant time."
fi
pho bw "${CARD_FLAG[@]}" images upload --force --plain "$IMAGES_DIR/$rbf_name"
echo
# Step 3: Set as active image
info "Step 3/4: Setting $rbf_name as active image on $card_label ..."
pho bw "${CARD_FLAG[@]}" images use "$rbf_name"
echo
# Step 4: Set as default for post-reboot
info "Step 4/4: Setting $rbf_name as default boot image on $card_label ..."
pho bw "${CARD_FLAG[@]}" images default "$rbf_name"
echo
# Verify
info "Update complete. Verifying final state:"
echo
pho bw "${CARD_FLAG[@]}" images current
echo
info "Done. The new bitfile ($rbf_name) is active and set as default."
info "No reboot required -- the image is already active on the FPGA."
}
# ── Entry point ──────────────────────────────────────────────────────────────
main() {
check_prereqs
if [[ $# -eq 0 ]]; then
usage
exit 0
fi
# Parse leading -c <card> if present
if [[ "$1" == "-c" ]]; then
[[ $# -ge 2 ]] || die "-c requires a card number"
CARD_FLAG=(-c "$2")
shift 2
[[ $# -ge 1 ]] || die "missing <path-to-rbf-file> after -c"
fi
case "$1" in
--status) show_status ;;
--list-releases|--list) list_releases ;;
--help|-h) usage; exit 0 ;;
-*) die "Unknown option: $1" ;;
*) do_update "$1" ;;
esac
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment