FPGA-Entwicklung automatisieren mit Jenkins, Vivado und GitHub auf Linux VPS
* Dieser Artikel enthält einen Affiliate-Link für UpCloud VPS.
Continuous Integration & Delivery für FPGA-Projekte
Continuous Delivery und Continuous Integration sind agile Softwareentwicklungsmethoden, die den Zyklus zwischen Code-Änderung und Deployment verkürzen. Durch Automatisierung zur Verifikation von Code-Änderungen und Erstellung von Release-Dateien werden Teams produktiver und effizienter.
Softwareunternehmen praktizieren Continuous Development seit Langem – doch die Methoden lassen sich ebenso gut für FPGA-Projekte nutzen. Dieses Tutorial zeigt, wie Sie einen Automatisierungsserver auf einem Virtual Private Server (VPS) mit Jenkins, Xilinx Vivado und dem Git/GitHub Source-Control-Management (SCM) einrichten.
Was ist Jenkins?
Der Jenkins-Automatisierungsserver ist ein kostenloses Open-Source-Programm in Java. Es läuft unter Windows oder Linux – wir nutzen Linux, da dies die gängigste Plattform für headless Server ist.
Jenkins läuft unter Linux als Daemon-Prozess, unter Windows als Dienst. Ein eingebauter Webserver, den Jenkins beim Start startet, stellt die Benutzeroberfläche bereit. Die meisten Nutzer interagieren über das Web-Interface. Neue Automatisierungsprojekte lassen sich hinzufügen und bestehende verwalten.
Das Bild oben zeigt die Hauptseite des Jenkins-Servers, den wir heute einrichten. Standardmäßig können nur eingeloggte Nutzer auf Jenkins zugreifen; für diesen Artikel habe ich öffentlichen Zugriff auf Teile meines *Demo-Servers aktiviert.
* Update: Demo-Server am 13. Mai 2020 abgeschaltet.
Auf der Hauptseite sehen Sie eine Liste von Jobs. Diese Jobs können beliebige Tasks enthalten, manuell über die Web-GUI ausgelöst werden – oder automatisch durch Skripte, Webhooks oder als Folge abgeschlossener Jobs. Daher der Begriff Automatisierungsserver.
In unserem Beispiel entspricht jeder Job einem VHDL-Modul in einem separaten GitHub-Repository. Jenkins führt Simulation und Build aus, wann immer ein Entwickler Code in eines der überwachten Git-Repos pusht. Schlägt ein Testbench fehl oder bricht der Build ab, markiert Jenkins den Job als fehlgeschlagen und sendet automatisch eine E-Mail an den Commit-Autor des fehlerhaften Codes.
Das Beispielprojekt
Automatisierungsserver sind besonders nützlich für Teams an größeren Projekten. Daher habe ich ein Beispiel-FPGA-Projekt aus acht Git-Repositories konstruiert: ein 7-Segment-Display-Counter aus dem Fast-Track-Kurs, portiert auf das Xilinx ZedBoard.
Links zu den acht Repos auf GitHub:
- packages (VHDL-Pakete)
- bcd_encoder (Modul)
- counter (Modul)
- digit_selector (Modul)
- output_mux (Modul)
- reset (Modul)
- seg7_encoder (Modul)
- seg7 (Top-Modul)
Jedes Repo enthält ein VHDL-Modul und dessen Testbench. Ausnahme: das packages-Repo mit nur drei VHDL-Paketen für Konstanten und Typen. Das seg7-Top-Modul enthält zusätzlich eine Constraints-Datei für Taktrate und Pin-Zuordnung der physischen Implementierung.
Großangelegte VHDL-Projekte nutzen Module aus mehreren Repositories. Firmen haben typischerweise Bibliotheken von Paketen und Modulen, die in vielen Designs wiederverwendet werden – das emuliere ich durch Aufsplitten dieses eher einfachen Designs in viele Module.
In unserem Beispiel sind alle Module vom packages-Repo abhängig, und das Top-Modul hängt von allen Submodulen ab. Gelöst habe ich dies durch Import als Git Submodules. Der Graph oben zeigt Inhalte und Abhängigkeiten aller Repos.
Die Git-Repos enthalten auch Nicht-Design-Dateien wie Jenkins-Konfiguration und Build-Skripte – darauf gehen wir in den folgenden Abschnitten ein.
Virtual Private Server (VPS)
Jenkins läuft auf jedem Windows- oder Linux-Rechner, aber praktisch wollen Sie es auf einem dedizierten Server betreiben. Der Automatisierungsserver muss immer laufen und für alle Teammitglieder erreichbar sein. Falls Sie einen physischen Server mit ausreichender Kapazität haben – gut. Für die meisten ist ein VPS schneller und günstiger.
Ein VPS ist ein virtueller Computer, den Sie bei einem Hosting-Anbieter mieten. Er verhält sich wie ein echter Windows- oder Linux-Rechner, auf dem Sie beliebige Software installieren können. Wir nutzen Linux, da es für unseren Use Case am sinnvollsten ist.
Die VHDLwhiz-Seite läuft seit zwei Jahren auf einem VPS. Ich habe bereits den schnellsten und besten VPS-Anbieter recherchiert: UpCloud. Natürlich nutzen wir UpCloud für unseren Automatisierungsserver.
25 $ UpCloud Bonus sichern
Falls Sie UpCloud testen möchten, habe ich einen Referral-Code, der 25 $ Guthaben bei Anmeldung gibt.
>> Hier klicken für 25 $ UpCloud Bonus <<
Oder Promo-Code beim Checkout nutzen: NV78V6
Damit erhalten Sie den Bonus und unterstützen VHDLwhiz gleichzeitig. Ich erhalte ggf. Gutschriften für jeden Kunden, der den Code nutzt.
Genug der Werbung – los geht's mit der Server-Einrichtung.
UpCloud VPS bereitstellen
Nach Login im UpCloud-Account: Server → Deploy Server.
Standort wählen (nächster Rechenzentrum). Plan wählen: Jenkins braucht wenig Ressourcen, aber Xilinx Vivado ist ein RAM-Fresser. Mindestens 4 GB RAM wählen (siehe Bild).
Ich empfehle einen Blick auf Xilinx' Memory Recommendations – Speicherverbrauch korreliert mit FPGA-Komplexität. Für Zynq-7000 XC7Z045 werden 1,9 GB Peak gelistet. Der 2-GB-Plan war zu wenig für Routing – Vivado stürzte ab mit Out of memory: Killed process (vivado) im dmesg-Log.
RAM/CPU lassen sich im UpCloud-Account einfach upgraden. Zusätzlicher Speicherplatz aus teureren Paketen erfordert Repartitionierung, aber es läuft. Referenz: Ich startete mit 50 GB Speicher, nach Abschluss des gesamten Automatisierungsservers 61 % genutzt. Vivado allein belegt 24 GB.
Als OS empfehle ich die neueste CentOS-Distribution (Bild). Xilinx Vivado unterstützt offiziell nur Red Hat Linux (nicht kostenlos). CentOS ist ein kostenloser, community-getragener Klon, der Red Hat eng folgt.
Netzwerk-Optionen auf Default belassen. SSH-Keys für passwortlosen Login hochladen (später auch konventionell möglich).
Hostname und Servername festlegen (Bild). Hostname = öffentliche Domain für Jenkins-Zugriff im Browser. Keine Domain? IP-Adresse funktioniert auch. Deploy drücken.
Nach Erstellung wird das autogenerierte Passwort als Benachrichtigung angezeigt. Später per passwd änderbar. Bei SSH-Key vor Deployment: Passwort nicht nötig. Zugriffverlust? Im UpCloud-Account: Open the console connection.
DNS-Zonen-Einstellungen
Neuer Server erhält permanente IPv4/IPv6-Adressen (UpCloud: Server → Network). SSH-Zugriff auf Root-Account der öffentlichen IPv4.
Beispiel-IP aus Bild: Befehl für Linux-Heimrechner:
IP-Adresse reicht für Experimente. Praktischer: permanente Domain. Domain bei Registrar kaufen.
Ich besitze vhdlwhiz.com, also Subdomain jenkins.vhdlwhiz.com erstellt. Domain auf UpCloud beim Deployment korrekt gesetzt. Nächster Schritt: Subdomain auf öffentliche IPv4 zeigen.
Bild zeigt DNS-Zonen-Einträge beim Registrar. Für Top-Level-Domain Hostname-Feld leer lassen. Für Subdomain „jenkins“ Namen eintragen.
DNS-Änderungen brauchen Zeit (meist ≤20 Min, extrem bis 48 h). Danach Domain statt IP für SSH nutzen:
ssh root@yoursub.yourdomain.com
Jenkins installieren
Nach SSH-Login als Root: alle Pakete aktualisieren. CentOS nutzt yum als Paketmanager.
yum -y update
System aktuell? Weiter mit Installation. Aber vor yum install jenkins explizit Java 11 installieren – vermeidet Probleme später bei Vivado-Installation.
Aktuell kein Java-Interpreter vorhanden. yum install jenkins würde Java 8 ziehen – gut für Jenkins, aber Vivado braucht Java 11.
yum -y install java-11-openjdk-devel
Jenkins nicht im Standard-Repo von CentOS. Jenkins-Repo von Red Hat importieren:
wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
Jenkins installieren:
yum -y install jenkins
Jenkins startet automatisch nach nächstem Boot, aber manuell starten ohne Reboot:
systemctl start jenkins
Status prüfen:
systemctl status jenkins
Jenkins über unsicheres HTTP
Jenkins läuft auf Port 8080, aber CentOS-Firewall blockiert Port 8080 und 80 (HTTP) standardmäßig. Port 80 in Firewall öffnen und per iptables auf 8080 umleiten.
Aber erst entscheiden: HTTPS gewünscht? Nur HTTP + Port 80 = unsichere Website. Öffentliches WLAN: Angreifer kann Login-Credentials stehlen.
Sicherheitsrisiko vermeiden? Nächster Abschnitt: HTTPS für Jenkins. Sonst weiterlesen.
Unsicheres HTTP aktivieren:
firewall-cmd --permanent --zone=public --add-port=80/tcp firewall-cmd --reload iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
Domain im Browser aufrufen → Jenkins Getting Started Seite. Chrome zeigt „Not secure“ Warnung.
Weiter zu Setting up Jenkins wenn okay.
Jenkins über sicheres HTTPS
Öffentlich zugängliche ungesicherte Website = großes Sicherheitsrisiko. Jenkins kann Source Code zugreifen – und jeder Hacker, der den Server knackt. Absicherung: wenige Copy-Paste-Befehle.
Jenkins kann HTTPS nicht selbst. Generischen Webserver installieren, der sichere Requests an unsicheren Jenkins weiterleitet. Ich nutze Nginx – populärer kostenloser Open-Source-Webserver.
yum -y install nginx systemctl start nginx
HTTP und HTTPS Ports in Firewall öffnen (HTTP für Redirect auf HTTPS nötig):
firewall-cmd --permanent --zone=public --add-port=80/tcp firewall-cmd --permanent --zone=public --add-port=443/tcp firewall-cmd --reload
Zertifikat installieren: kostenlose Let's Encrypt CA. Certbot-Skript automatisiert das.
apt update apt install snapd snap install core; snap refresh core snap install --classic certbot
Skript ausführen – installiert Zertifikat und passt Nginx-Config an. Während Lauf: Fragen bejahen (Yes, Accept) bis zur Frage: HTTP auf HTTPS umleiten? Empfehlung: Option 2 (Redirect).
... Deploying Certificate to VirtualHost /etc/nginx/nginx.conf Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. 1: No redirect 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites... Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Täglichen Cron-Job für Zertifikatserneuerung einrichten:
echo "0 0 * * * /snap/bin/certbot renew --quiet" | crontab -
Cron läuft täglich Mitternacht. crontab -l listet Jobs, crontab -e bearbeitet.
Website besuchen → Nginx Testseite (nicht Jenkins). „Not secure“ Warnung in Chrome weg? Gut.
Nginx für Jenkins konfigurieren: /etc/nginx/nginx.conf bearbeiten (Code-Snippet Credit: Kerren's Blog auf Medium). nano Editor nutzen:
nano /etc/nginx/nginx.conf
Server-Block mit Ihrer Domain finden, hervorgehobene Zeilen aus Listing hinzufügen (erste Zeile oberhalb Server-Block, Rest in root location Block).
Config testen, dann Nginx neu laden:
nginx -t systemctl reload nginx
Jenkins-Seite im Browser → Getting Started Page über sichere Verbindung. Sicher weiter konfigurieren.
Jenkins einrichten
Erster Besuch: Passwort aus Datei auf Linux-Filesystem. Per SSH:
cat /var/lib/jenkins/secrets/initialAdminPassword
Kopieren, im Browser einfügen → Web-GUI Zugriff.
Nächster Bildschirm: Install suggested plugins wählen (später anpassbar).
Admin-User anlegen: Details ausfüllen, starkes Passwort. Standard: nur eingeloggte Nutzer haben Zugriff. Anonyme sehen nur Login-Dialog. Mein *Demo-Site war zugänglich, da ich Matrix Authorization Strategy Plugin für anonymen Zugriff auf einige Views nutzte.
* Update: Demo-Site am 13. Mai 2020 abgeschaltet.
Nach Plugin-Installation: „Jenkins is ready!“ Button → leere Übersichtsseite der frischen Installation.
Jenkins Plugins installieren
Sidebar: Manage Jenkins → Manage Plugins → Available. Suche funktioniert erst nach Eingabe im Suchfeld.
Blue Ocean
Erstes empfohlenes Plugin: Blue Ocean. Modernisiert Jenkins Workflow und UI, zieht viele nützliche Plugins nach. „blue ocean“ suchen, installieren. Option: Restart Jenkins when installation is complete and no jobs are running. Oder per SSH:
systemctl restart jenkins
Neuer Menüpunkt in Sidebar → Blue Ocean GUI (anders als klassisches Jenkins). Ausprobieren!
Green Balls
Rein ästhetisch. Standard: blaue Bälle für erfolgreiche Jobs (Erfinder ist Japaner – in Japan steht Blau für OK). Green Balls Plugin ändert auf grün. „green ball“ suchen, installieren.
Locale Plugin
Erzwingt einheitliche Sprache im Jenkins-GUI für alle Nutzer. Standard: Browser-Sprache. Ich bin Norweger, möchte aber Englisch (Übersetzung unzureichend, Googeln auf Englisch einfacher). „locale“ suchen, installieren.
Falls installiert: Manage Jenkins → Configure System → Sektion Locale → „en_US“ (oder gewünschte Sprache) eintragen, Haken bei Force this language for all users setzen. Save nicht vergessen.
Sidebar Link Plugin
Ermöglicht benutzerdefinierte Links in der Jenkins-Sidebar. Später für Link zu FPGA-Releases (Bitfiles). „sidebar“ suchen, installieren.
Jenkins mit GitHub verbinden
Öffentlich oder privat: Jenkins braucht Berechtigungen auf GitHub-Account. Einfachster Weg: Jenkins GitHub Plugin (via Blue Ocean installiert) managt Interface.
Personal Access Token in GitHub
GitHub anmelden → Profilbild → Settings → Developer Settings → Personal access tokens (oder Direktlink).
Generate new token klicken. GitHub fragt Passwort. Erstellen eines anwendungsspezifischen Passworts – widerrufbar, berechtigungsbeschränkt.
Token benennen (z. B. „Jenkins“). Mindestens admin:org_hook, admin:repo_hook, repo Berechtigungen setzen (Bild). Rest unchecked.
Generate token → Access Code erscheint. Kopieren bevor Seite verlassen! Nicht wieder einsehbar. Vergessen? Token löschen, neu erstellen.
GitHub-Credentials in Jenkins eintragen
Jenkins: Manage Jenkins → Configure System → Sektion GitHub → Dropdown: Add GitHub Server → GitHub Server.
Neuer GitHub Server Abschnitt: Manage hooks anhaken (Jenkins installiert Webhooks auf GitHub für überwachte Repos – nützlich für Trigger bei Code-Push).
Credentials (Add) → Jenkins wählen.
Fenster: Kind Dropdown → Secret text. Personal Access Token in Secret Feld. ID: „GitHub“. Add drücken.
Zurück im Hauptconfig-Menü: neuen GitHub Key aus Credentials Menü wählen. Test connection → Erfolgsmeldung.
Seitenende: Save klicken bevor Config-Seite verlassen.
Mehrere Credentials versehentlich hinzugefügt? Manage Jenkins → Manage Users → eigenen User → Sidebar Credentials → Verwalten/Löschen.
E-Mail-Versand aus Jenkins konfigurieren
Automatisierte E-Mails bei Code-Fehlern. Manage Jenkins → Configure System anpassen.
1. System Admin e-mail address Feld: Absenderadresse eintragen. Am besten mit Jenkins-Domain endend (minimiert Spam-Filter). Jenkins-Server darf nicht für andere Domains senden, aber die meisten Mail-Services akzeptieren Absender mit gleicher Domain wie sendender Server.
2. SMTP-Server auf VPS installieren:
yum -y install sendmail systemctl enable sendmail systemctl restart sendmail
Jenkins System Config: SMTP server = „localhost“.
Haken bei Allow sending to unregistered users (Nutzer ohne Jenkins-Account). Später: E-Mail an Person, die fehlerhaften Code pusht. Jenkins holt E-Mail von GitHub – funktioniert nur bei passendem Jenkins-Account oder gesetztem Haken.
Test: Test configuration → „Email was successfully sent“ → Posteingang prüfen (Spam-Ordner checken).
Xilinx Vivado im Batch-Modus installieren
Ich nutze Xilinx Vivado für Simulation, Kompilierung, Implementation. Target: Xilinx Zynq-7000 FPGA auf ZedBoard. Installation mit kostenloser WebPACK-Lizenz.
Schritt 1: Xilinx Unified Installer herunterladen
Linux Self Extracting Web Installer (Bild). Xilinx-Account nötig für Download.
Schritt 2: Installer auf Jenkins-Server kopieren
Download abgeschlossen → von Desktop auf Jenkins-Server kopieren. Linux-Shell auf Desktop? scp nutzen.
Schritt 3: Vivado-Abhängigkeiten installieren
yum -y install tar yum -y install java-11-openjdk-devel yum -y install ncurses-compat-libs yum -y install gcc
Schritt 4: Xilinx Unified Installer entpacken
./Xilinx_Unified_2019.2_1106_2127_Lin64.bin --keep --noexec --target Xil_installer
.bin entpackt in Verzeichnis Xil_installer. Fehler Uncompressing Xilinx Installer Extraction failed. Terminated → tar nicht installiert.
Schritt 5: Gewünschte Tools auswählen
cd Xil_installer/ ./xsetup -b ConfigGen
xsetup fraggt Tools ab. „2“ für Vivado, dann „1“ für Vivado HL WebPACK:
Select a Product from the list: 1. Vitis 2. Vivado 3. On-Premises Install for Cloud Deployments 4. BootGen 5. Lab Edition 6. Hardware Server 7. Documentation Navigator (Standalone) Please choose: 2 Select an Edition from the list: 1. Vivado HL WebPACK 2. Vivado HL Design Edition 3. Vivado HL System Edition Please choose: 1
Schritt 6: Authentifizierung für WebPACK
Installation erfordert Xilinx-Account-Login. Desktop: GUI führt durch. Server: kein GUI → xsetup Skript für Auth.
./xsetup -b AuthTokenGen
Bei mir paar Versuche nötig. Erst Fehler „Internet connection validated, can connect to internet.“ Nach paar Versuchen durchgekommen – User ID und Passwort (E-Mail/Passwort vom xilinx.com Download) eingeben.
Schritt 7: Vivado im Batch-Modus installieren
Config-File in ~/.Xilinx/install_config.txt. Installation starten:
./xsetup -a XilinxEULA,3rdPartyEULA,WebTalkTerms \ -b Install -c ~/.Xilinx/install_config.txt
Dauert lange. Vivado Installation: 24 GB. Download von langsamen Xilinx-Server: bei mir >2 Stunden.
Schritt 8: Vivado Batch-Modus testen
Xilinx liefert Shell-Skript für Environment-Setup. Vor Vivado-Ausführung sourcen:
source /tools/Xilinx/Vivado/2019.2/settings64.sh
Vivado im Batch-Modus starten (kein GUI auf Server):
vivado -mode batch -version
Startet und beendet sofort ohne Fehler → Vivado bereit. Fehler libtinfo.so.5: cannot open shared object file → ncurses-compat-libs fehlt (siehe Abschnittsbeginn).
Vivado in Jenkins integrieren
Manage Jenkins → Configure System → Defaults prüfen.
Vivado braucht viel RAM (Xilinx Memory Recommendations Page). Default parallele Jobs von 2 auf 1 reduzieren (außer riesiges RAM auf VPS). # of executors = 1 setzen.
Environment-Variablen global für alle Jobs definieren (statt pro Job). Global properties → Environment variables anhaken → Add. Standard Linux PATH mit einbeziehen. Ich nutzte: „PATH=/tools/Xilinx/Vivado/2019.2/bin:/sbin:/usr/sbin:/bin:/usr/bin“. Save nicht vergessen.
Vivado GUI-Projekte im Batch-Modus
Ich manage Vivado-Projekte im GUI-Modus. Pro Repo: neues Projekt in Vivado GUI, Source-Files hinzufügen, Libraries setzen, etc. Aber .xpr Projektdateien sind binär und abhängen von vielen Temp-Dateien – ungeeignet für Git.
Xilinx hat Guideline (XAPP1165) für Vivado mit Version Control: write_project_tcl Befehl exportiert ganzes Projekt in Tcl-Skript – menschenlesbar, Git-geeignet.
Repos organisiert: Vivado-Dateien in Unterordner „vivado“, VHDL-Sources im Parent-Verzeichnis. Demo packages Projekt auf GitHub anschauen. Pro Repo: Vivado Tcl-Skripte in vivado Ordner. create_vivado_proj.tcl = menschenlesbare Version des Vivado-Projekts.
create_vivado_proj.tcl erzeugen
Vivado-Projekt in GUI einrichten (Projekt in vivado Unterordner). Zufrieden? Tcl Console:
cd [get_property DIRECTORY [current_project]] write_project_tcl -force -target_proj_dir . create_vivado_proj
create_vivado_proj.tcl zu Git hinzufügen, .gitignore ignoriert Rest des Vivado-Projekts. Mein .gitignore ignoriert alles außer Tcl-Skripts in vivado Ordner.
Vivado-Projekt im Batch-Modus öffnen (Test)
Vor Jenkins-Jobs manuell auf VPS testen. Jenkins-Daemon läuft unter User jenkins. Also mit jenkins User testen.
Git auf Linux-Server installieren (als Root):
yum -y install git
Zu jenkins User wechseln:
su - jenkins
pwd → /var/lib/jenkins (kein regulärer User unter /home, nur für Jenkins-Daemon, aber Login für manuellen Walkthrough möglich).
Home voller dynamischer Daten (Logs, Settings, Plugins). Später erscheinen Jobs im jobs Ordner.
Ins jobs Verzeichnis:
cd /var/lib/jenkins/jobs/
Git-Repo direkt in jobs klonen (passwortlos: public oder SSH-Key Setup).
Kein eigenes Repo? Meins klonen:
git clone https://github.com/jonasjj/Jenkins-demo-packages
cd in Repo, weiter in vivado:
cd Jenkins-demo-packages/vivado/
Zwei Tcl-Dateien: create_vivado_proj.tcl und check_syntax.tcl (Syntax-Check für VHDL-Dateien im Vivado-Projekt).
Vor Vivado-Befehlen PATH in aktueller Shell setzen (in Jenkins via Global Properties gelöst, hier manuell):
source /tools/Xilinx/Vivado/2019.2/settings64.sh
Projekt neu erstellen:
vivado -mode batch -source create_vivado_proj.tcl
Viel Tcl-Code auf Console. Keine offensichtlichen Fehler?
echo $?→ 0 = Erfolg.
echo $? zeigt Exit-Status des vorherigen Befehls. 0 = OK, alles andere = Fehler. Wichtig für Jenkins: Job-Stage Success/Failure Entscheidung.
Directory Listing zeigt neu erstellte binäre Projektdateien.
Weitere Test: One-Liner Tcl-Skript erstellen, in Vivado Batch ausführen, Exit-Code prüfen. exit 0 → Success, exit 1 → Failure. exit Keyword ist Standard Tcl – Interface zwischen Vivado und Jenkins. Jenkins führt Tcl-Skript aus, prüft Exit-Status für Job-Status.
Testprojekt löschen:
cd /var/lib/jenkins/jobs/ rm -rf Jenkins-demo-packages
Tcl-Skript: VHDL-Syntax-Check in Vivado
Führt Syntax-Check der VHDL-Dateien im Projekt aus. Für Simulation/Implementation unnötig (Syntaxfehler brechen Kompilierung). Aber packages-Projekt hat keine Testbench – nur Konstanten/Typen. Trotzdem Coding-Fehler bei Push abfangen wollen → Syntax-Check.
Skript check_syntax.tcl:
# Check for syntax errors
# Return exit code 1 on error, else 0
open_proj packages.xpr
set msg [check_syntax -fileset sim_1 -return_string]
set ret_val 0
if {$msg != ""} {
set ret_val 1
}
puts $msg
exit $ret_val
Vivado unterstützt Standard-Tcl-Keywords und viele Built-in-Commands wie check_syntax. Details in Xilinx Docs:
- Vivado Design Suite Tcl Command Reference Guide (UG835)
- Vivado Design Suite User Guide Using Tcl Scripting (UG894)
Tcl-Skript: Simulation in Vivado
run_simulation.tcl für Testbench im Batch-Modus. Voraussetzung: Simulation Sets in Vivado GUI konfigurieren vor Export zu Tcl. Ein Simulationsprojekt auf Desktop via create_vivado_proj.tcl neu erstellen → Setup anschauen. Rekonstruierte Projekte in Vivado GUI öffnen.
Skript:
open_proj seg7.xpr set sim_fileset sim_1 launch_simulation -simset [get_filesets $sim_fileset] close_sim # Look for assertion failures in simulation log set log_file [glob *sim/$sim_fileset/behav/xsim/simulate.log] set fp [open $log_file] set file_data [read $fp] exit [regex "Failure:" $file_data]
Simulation-Status ermitteln: VHDL Testbenches beenden bei Erfolg mit finish. Fehler → VHDL Assertion Failure. Kein offensichtlicher Tcl-Weg in Vivado, Abbruchgrund zu finden.
Workaround: Simulationslog öffnen, nach String „Failure:“ suchen (zeigt VHDL Assertion Failure). Exit 1 wenn im Log, sonst 0.
Tcl-Skript: Synthese in Vivado
run_synthesis.tcl:
open_proj seg7.xpr
set run_name synth_1
set cpu_count 4
reset_runs $run_name
launch_runs $run_name -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "synth_design Complete!"} {
exit 1
}
exit 0
launch_runs non-blocking → Status direkt nach Aufruf „Running“. wait_on_run pausiert bis Synthese Abschluss. Run-Status prüfen, Exit 0/1.
cpu_count = logische Prozessoren des Servers (mein UpCloud VPS: 4 CPUs → 4).
Tcl-Skript: Implementation (Place & Route) in Vivado
run_implementation.tcl – ähnlich Synthese, aber Run-Name „impl_1“, anderes Success-Message:
open_proj seg7.xpr
set run_name impl_1
set cpu_count 4
reset_runs $run_name
launch_runs $run_name -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "route_design Complete!"} {
exit 1
}
exit 0
Tcl-Skript: Bitstream-Generierung in Vivado
generate_bitstream.tcl – nach erfolgreicher Implementation:
open_proj seg7.xpr
set run_name impl_1
set cpu_count 4
launch_runs $run_name -to_step write_bitstream -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "write_bitstream Complete!"} {
exit 1
}
exit 0
Jenkins Jobs einrichten
Job in Jenkins = Gruppe von Software-Tasks. Übersichtsseite listet Jobs mit Status. Manuell startbar oder automatisch (Push auf Repo, Abschluss anderer Jobs).
Jenkins bietet: klassisch Freestyle project (Aktionen in Web-GUI) oder modern Pipeline (Skript speichert Ausführungsfluss – versionierbar im SCM).
Neue Pipeline: Sidebar New item → Pipeline → OK.
Job-Config: GitHub project anhaken, Project url eintragen (hier packages-Repo, Prozedur identisch für alle).
Build Triggers: Job starten bei Push auf GitHub Repo → GitHub hook trigger for GITScm polling anhaken (funktioniert nur wenn Manage hooks in Global Settings gesetzt).
Pipeline-Sektion unten: Pipeline script from SCM wählen (Git selected). Repo-URL einfügen, Credentials falls privat (unser public → leer). Default branch master. Pfad zu Jenkins-Skript im Repo: Jenkinsfile im Root jedes Repos. Save.
Jenkins Pipeline-Skripte
Syntax: Apache Groovy (nie gehört, aber verständlich bei Programmiererfahrung). Sieht wie JSON ohne Kommas aus. Vielseitig: Stages parallel, Multi-Server. Offizielle Jenkins Pipeline Doku für Tiefe.
Template für alle Skripte:
pipeline {
agent any
stages {
stage('Stage name 1') {
steps {
// Command 1
// Command 2
}
}
stage('Stage name 2') {
steps {
// Command 1
}
}
}
post {
failure {
emailext attachLog: true,
body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
Fehlerhafter Push → Verursacher erhält automatisierte E-Mail mit Failed-Job-Info. failure in post Sektion → führt nur aus wenn Stage fehlschlägt. Job stoppt, springt in failure. Jenkins zieht E-Mail-Adressen aus letzten Git-Commits, sendet Link zum broken Build.
VHDL Syntax-Check Job (packages Repo)
Einziges Repo ohne Testbench → check_syntax.tcl prüft valides VHDL.
Jenkinsfile:
pipeline {
agent any
stages {
stage('Create project') {
steps {
deleteDir() // workspace bereinigen
git 'https://github.com/jonasjj/Jenkins-demo-packages'
sh 'cd vivado && vivado -mode batch -source create_vivado_proj.tcl'
}
}
stage('Check VHDL syntax') {
steps {
sh 'cd vivado && vivado -mode batch -source check_syntax.tcl'
}
}
}
post {
failure {
emailext attachLog: true,
body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
Stage 1: deleteDir() bereinigt Workspace. git (Jenkins Plugin, nicht Linux-Befehl) klont Repo. Shell: vivado Dir wechseln, create_vivado_proj.tcl ausführen.
Stage 2: Projekt existiert → check_syntax.tcl ausführen. Exit 0 = Success, 1 = Failure → Jenkins markiert Build als failed.
VHDL Simulations-Jobs (alle anderen Repos außer packages)
git One-Liner funktioniert nicht – Repos haben Submodule-Abhängigkeiten. git Befehl zieht Submodules nicht standardmäßig. Fix: vielseitigerer checkout Call (Git Plugin Doku).
Jenkinsfile (bcd_encoder Repo):
pipeline {
agent any
stages {
stage('Create project') {
steps {
deleteDir()
checkout([$class: 'GitSCM',
branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [[
$class: 'SubmoduleOption',
disableSubmodules: false,
parentCredentials: false,
recursiveSubmodules: true,
reference: '',
trackingSubmodules: true
]],
submoduleCfg: [],
userRemoteConfigs: [[
url: 'https://github.com/jonasjj/Jenkins-demo-bcd_encoder'
]]
])
sh 'cd vivado && vivado -mode batch -source create_vivado_proj.tcl'
}
}
stage('Run simulation') {
steps {
sh 'cd vivado && vivado -mode batch -source run_simulation.tcl'
}
}
}
post {
failure {
emailext attachLog: true,
body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
Identische Skripte (nur andere Repo-URLs) für counter, digit_selector, output_mux, reset, seg7_encoder.
FPGA Implementation Job (seg7 Top-Modul Repo)
seg7 Repo enthält Top-Modul, zieht alle anderen Repos als Submodules. Pipeline ähnlich Simulations-Jobs, aber vier zusätzliche Stages: Run simulation, Run synthesis, Run implementation, Generate bitstream, Release bitfile.
Erste zwei Stages (Projekt erstellen, Simulation) bereits abgedeckt. Nächste drei Stages analog mit entsprechenden Tcl-Skripts.
Jenkinsfile:
pipeline {
agent any
stages {
stage('Create project') { ... }
stage('Run simulation') { ... }
stage('Run synthesis') {
steps { sh 'cd vivado && vivado -mode batch -source run_synthesis.tcl' }
}
stage('Run implementation') {
steps { sh 'cd vivado && vivado -mode batch -source run_implementation.tcl' }
}
stage('Generate bitstream') {
steps { sh 'cd vivado && vivado -mode batch -source generate_bitstream.tcl' }
}
stage('Release bitfile') {
steps {
sh '''
PROJ_NAME=seg7
RELEASE_DIR=/usr/share/nginx/html/releases/
BASE_NAME=$PROJ_NAME-`date +"%Y-%m-%d-%H-%M"`
BITFILE=$BASE_NAME.bit
INFOFILE=$BASE_NAME.txt
git log -n 1 --pretty=format:"%H" >> $INFOFILE
echo -n " $PROJ_NAME " >> $INFOFILE
git describe --all >> $INFOFILE
echo "" >> $INFOFILE
echo "Submodules:" >> $INFOFILE
git submodule status >> $INFOFILE
cp $INFOFILE $RELEASE_DIR
cp vivado/seg7.runs/impl_1/top.bit $RELEASE_DIR/$BITFILE
'''
}
}
}
post { failure { ... } }
}
Finale Stage Release bitfile: Shell-Skript kopiert neu generiertes FPGA-Programmierfile in Release-Ordner. Dateiname: Projektname + Timestamp.
Traceability: Textdatei mit Git-Hash des Main-Repos (seg7) und aller Submodules. Bei Git Submodules reicht Main-Repo-Hash nicht – Änderungen in Submodules nicht enthalten. Main-Repo nach Pull/Update aller Submodules committen? Nicht automatisch von Jenkins gewollt.
Hinweis: FPGA-Implementation bei jedem Push (wie im Beispiel) ist für echtes Jenkins-Projekt oft nicht gewollt. Große Projekte: Stunden Buildzeit, Team pusht mehrmals täglich. Stattdessen: Jenkins auf täglichen Build konfigurieren (z. B. Mitternacht – Screenshot Job-Config).
Builds nach Abschluss anderer Jobs triggern
Beispielprojekt: mehrere Git-Repos, als Submodules verknüpft. Außer packages: alle hängen von mindestens einem anderen Repo ab. Meist von packages. Dependency Graph früher im Artikel.
Jobs nicht nur bei Push auf eigenes Repo triggern, sondern auch nach Abschluss von Submodule-Jobs. In Jenkins: jedes Job besuchen, Build after other projects are built entsprechend setzen.
Bild: Trigger für bcd_encoder – startet nach erfolgreichem Build von packages (Abhängigkeit).
Top-Modul hängt von allen anderen ab → als Watch-Projekte in Komma-getrennter Liste hinzufügen (Bild). Hinweis: Für FPGA-Implementation-Job bei langer Route-Time evtl. nicht gewollt (siehe vorheriger Abschnitt).
Bitfiles via Nginx bereitstellen
Webserver läuft bereits → für Release-Files über HTTP nutzen. Ziel: neue Bitfiles unter jenkins.vhdlwhiz.com/releases.
Implementation-Job kopiert Bitfiles bereits in Verzeichnis auf Nginx HTML-Root – Verzeichnis erstellen:
mkdir /usr/share/nginx/html/releases/ chown jenkins.root /usr/share/nginx/html/releases/
/etc/nginx/nginx.conf anpassen: Server-Sektion mit Domain finden, folgende Location-Sektion direkt unter root (/) Location einfügen:
location ^~ /releases {
alias /usr/share/nginx/html/releases/;
autoindex on;
}
Config testen, Nginx neu laden:
nginx -t systemctl reload nginx
Erfolg → Release-Verzeichnis auflistbar (Chrome Screenshot).
Jenkins Web-Interface mit Release-Dir verknüpfen: Sidebar Link Plugin (bereits installiert) für Custom Link in Sidebar.
Manage Jenkins → Configure System → Additional Sidebar Links → Name und URL angeben (Bild). Link-Icon optional (Jenkins-Icon wiederverwendet).
Ergebnis: Custom Link zu Bitfile-Releases in Sidebar mit Ordner-Icon (Bild).
Zusammenfassung
Jenkins ist wertvolles Tool auch für FPGA-Teams. Automatisierung spart Zeit, verbessert Codequalität. Automatische Build-Triggers und Pipeline-Skripts: weniger Coding-Fehler bleiben unentdeckt.
Beispielprojekt zeigt: Jenkins implementiert komplette Regressions-Test-Suite für VHDL-Code. Zeigt Projekt-Health in grafischer Web-Oberfläche – verständlich auch für VHDL-unerfahrene Projektmanager.
Jenkins für FPGA-Entwicklung ausprobieren? Schritte dieses Artikels auf UpCloud VPS folgen. Ich habe vor Jahren alle VPS-Anbieter recherchiert bevor VHDLwhiz auf VPS zog. UpCloud war schnellste und beste Alternative. Noch 100 % zufrieden.
UpCloud-Account eröffnen? Bitte meinen Referral-Link oder Code nutzen: NV78V6. Unterstützt VHDLwhiz und Sie erhalten 25 $ Guthaben auf UpCloud mit Promo-Code.
VHDL
- VHDL Dual-7-Segment-Display-Controller für Pmod SSD – Einfache FPGA-Integration
- BMP-Bitmap-Bilder in VHDL-Testbenches mit TEXTIO einlesen
- Ihr erstes VHDL-Programm: Schritt-für-Schritt Hello World Tutorial
- Konstanten und Generic Maps in VHDL für flexible Moduldesigns nutzen
- VHDL-Testbench-Simulation sauber beenden
- Atmende LED-Effekt mit Sinuswelle aus Block RAM erzeugen
- For-Schleifen in VHDL meistern: Ein praktischer Leitfaden
- Dynamische verkettete Liste in VHDL mit Protected Types und Access-Pointern
- VHDL Port Map Instanziierung meistern: Praktischer Leitfaden
- std_logic_vector in VHDL meistern: Signalvektoren erstellen