Sweeps de timing et de seeds ECP5
Hazard3-Doom exécute plusieurs routages nextpnr-ecp5 afin de caractériser le
timing ECP5, choisir des seeds utiles, comparer les paramètres de placement et
de routage, et détecter les régressions de timing après une modification du RTL
ou d’un coeur généré. Les mêmes scripts de sweep sont utilisés localement et par
le workflow GitHub Actions ECP5 seed sweep.
Un sweep n’est pas seulement une recherche d’un seed chanceux. C’est aussi une expérience reproductible : synthétiser un netlist une seule fois, router exactement ce netlist avec plusieurs seeds, enregistrer la chaîne d’outils et la configuration, puis comparer tous les domaines d’horloge requis.
Pourquoi les seeds comptent
nextpnr utilise le seed pour influencer certaines décisions aléatoires du placement et du routage. Des seeds différents explorent donc des implémentations physiques différentes du même design synthétisé. Un seed peut améliorer un domaine d’horloge tout en dégradant un autre.
Le numéro du seed n’indique pas sa qualité. Un seed qui passait avec un ancien netlist ne doit être considéré que comme une référence historique après une modification importante du RTL, du coeur LiteDRAM généré, des horloges, de la géométrie mémoire, du framebuffer, des contraintes, de la synthèse ou des outils CAD.
Pour une comparaison A/B utile, utilisez le même ensemble de seeds pour chaque configuration.
Définition d’un PASS de timing
Un seed routé ne passe que si toutes les horloges requises de la cible passent dans le même routage.
Cible |
|
Utilisateur LiteDRAM |
Pixel vidéo |
TMDS x5 |
Init LiteDRAM |
|---|---|---|---|---|---|
ULX3S 85F |
50 MHz |
n/a |
50 MHz |
250 MHz |
n/a |
ULX3S 12F |
40 MHz |
n/a |
50 MHz |
250 MHz |
n/a |
ULX4M-LD 85F |
Choisie par le workflow ; 40 MHz par défaut |
60 MHz |
50 MHz |
250 MHz |
25 MHz |
Une ligne telle que 1 warning, 0 errors ne suffit pas pour déterminer l’état du timing. Un processus de routage peut se terminer avec succès tout en donnant un statut
FAIL de timing. Le sweep utilise volontairement le mode
timing-allow-fail de nextpnr pour conserver les mesures des routages qui ne
ferment pas le timing.
Point de contrôle ULX4M-LD qualifié à 40/60 MHz
Le point de contrôle ULX4M-LD actuellement qualifié sur matériel utilise :
Hazard3/AHB: 40 MHz
LiteDRAM user: 60 MHz
LiteDRAM reference: 25 MHz
LiteDRAM init: 25 MHz
LiteDRAM init CPU: SERV
nextpnr placer: heap
timingweight: 30
critexp: 3
timing-driven rip-up: enabled
seed: 2
Le SHA256 de la netlist synthétisée et figée est :
160c536b12e46667990c887571da6f443ccc6c5a2ba644033db43fc783ea9453
Pour cette netlist exacte, le seed 2 a atteint 43,94 MHz pour clk_sys et
67,81 MHz pour l’horloge utilisateur LiteDRAM, satisfaisant les exigences 40/60
MHz. Le SHA256 exact du bitstream testé localement sur matériel est :
294602982dfc4a9906961f2e8b6f43de925d8c11a7e5e6bb0f5e392965a868de
La même netlist et les mêmes seeds ne fermaient pas de façon fiable avec les
anciens paramètres HeAP timingweight=10, critexp=2 et sans rip-up. C’est
pourquoi les métadonnées du sweep doivent enregistrer le réglage du
placeur/routeur en plus du seed et du hash de la netlist.
Le timing statique a été suivi d’une vraie qualification DDR sur la carte équipée
de Micron. Le routage a réussi le test séquentiel 1 Mio, le test clairsemé
complet d’alias sur 64 Mio, le test pseudo-aléatoire sur quatre régions, les
qualifications q répétées, le stress du tas 40 Mio, le test rapide
mémoire/timer de Doom et l’exécution RV32 copiée depuis la DDR. Ne qualifiez pas
un nouveau routage sur matériel uniquement à partir du timing nextpnr.
Pour reproduire l’expérience de routage connue comme bonne sur une netlist déjà figée et correspondante :
SWEEP_SKIP_SYNTH=1 \
SWEEP_JOBS=1 \
SWEEP_ROUTE_TIMEOUT_SECONDS=1200 \
SWEEP_NEXTPNR_HEAP_TIMINGWEIGHT=30 \
SWEEP_NEXTPNR_HEAP_CRITEXP=3 \
SWEEP_NEXTPNR_TMG_RIPUP=1 \
./scripts/sweep-ecp5.sh ulx4m-ld-85f 2
N’utilisez SWEEP_SKIP_SYNTH=1 qu’après avoir vérifié le hash de la netlist
figée et toutes les métadonnées du profil. Une reconstruction du préchargement du
moniteur, un profil de périphérique DDR, un cœur LiteDRAM généré, une horloge,
une modification RTL ou un changement d’outil de synthèse invalide la comparaison
avec la netlist figée et exige une nouvelle synthèse puis un nouveau sweep.
Conserver un bitstream ULX4M-LD pour test matériel
Le sweep ULX4M-LD enregistre normalement les journaux/résultats de timing et n’a pas besoin d’empaqueter chaque routage exploratoire. Lorsqu’un seed mérite un test matériel, conservez explicitement une configuration texte nextpnr. Pour l’expérience seed 2 qualifiée :
SWEEP_SKIP_SYNTH=1 \
SWEEP_JOBS=1 \
SWEEP_ROUTE_TIMEOUT_SECONDS=1200 \
SWEEP_NEXTPNR_HEAP_TIMINGWEIGHT=30 \
SWEEP_NEXTPNR_HEAP_CRITEXP=3 \
SWEEP_NEXTPNR_TMG_RIPUP=1 \
SWEEP_NEXTPNR_EXTRA_ARGS="--textcfg build/ulx4m-ld-test/fpga_ulx4m_ld-seed2.config" \
./scripts/sweep-ecp5.sh ulx4m-ld-85f 2
Empaquetez ensuite cette configuration déjà routée sans relancer nextpnr :
ecppack \
--compress \
--svf build/ulx4m-ld-test/fpga_ulx4m_ld-seed2.svf \
--idcode 0x01113043 \
build/ulx4m-ld-test/fpga_ulx4m_ld-seed2.config \
build/ulx4m-ld-test/fpga_ulx4m_ld-seed2.bit
N’utilisez pas un script pratique de génération de bitstream qui relance silencieusement nextpnr avec des paramètres de placement différents/par défaut ; il créerait un autre routage que celui du résultat de timing en cours de qualification. Vérifiez le hash de la netlist, les réglages de routage, le seed et le SHA256 final du bitstream avant le test matériel.
Sweep local
Le répartiteur de cibles est scripts/sweep-ecp5.sh. Les scripts spécifiques
aux cartes offrent des points d’entrée directs :
./scripts/sweep-ecp5.sh --list-targets
./scripts/sweep-ulx3s-85f.sh 1-32
./scripts/sweep-ulx3s-12f.sh 1-32
./scripts/sweep-ulx4m-ld.sh 1-32
SWEEP_JOBS contrôle le parallélisme local :
SWEEP_JOBS=8 ./scripts/sweep-ulx4m-ld.sh 1-32
Chaque processus nextpnr peut consommer plusieurs centaines de Mio. Une valeur
élevée de SWEEP_JOBS n’est utile que si le CPU, la RAM, le stockage et le
système hôte peuvent suivre.
Plusieurs routages nextpnr-ecp5 peuvent être exécutés en parallèle en local.
Dimensionnez SWEEP_JOBS selon la machine.
Le flux synthétise normalement une seule fois puis réutilise le même netlist
pour tous les seeds. N’utilisez SWEEP_SKIP_SYNTH=1 que si le netlist existant
correspond réellement aux sources, horloges et options courantes.
Sweep GitHub Actions
Le workflow est actuellement
.github/workflows/ulx4m-ld-seed-sweep.yml. Son nom affiché est
ECP5 seed sweep et le sélecteur de cible prend en charge ULX3S 85F,
ULX3S 12F et ULX4M-LD 85F.
Le workflow est lancé manuellement avec workflow_dispatch et sépare
volontairement la synthèse du routage afin que tous les jobs de routage utilisent
le même netlist figé.
La concurrence est groupée par cible et référence Git avec
cancel-in-progress: false : un second lancement de la même cible/référence
ne doit donc pas annuler un sweep déjà en cours de collecte.
Paramètres du workflow
Paramètre |
Défaut actuel |
Utilisation |
|---|---|---|
|
|
Cible FPGA : |
|
1 / 260 |
Plage inclusive. Le workflow actuel impose 1 à 260. Pour les expériences, commencez par une plage plus petite. |
|
20 |
Nombre maximal de jobs GitHub de routage simultanés : 4, 8, 12 ou 20. |
|
2 |
Nombre de seeds routés en série dans chaque job : 1 à 5. Deux limite l’impact d’un seed exceptionnellement lent. |
|
false |
Conserver les |
|
1 |
Active les modes HDMI étendus de l’ULX3S 85F. |
|
|
Profil SDRAM 12F : |
|
40 |
Horloge système Hazard3 de l’ULX4M-LD : 25, 40 ou 50 MHz. Le domaine utilisateur LiteDRAM reste séparé à 60 MHz. |
|
|
CPU intégré au coeur d’initialisation LiteDRAM : |
|
|
HeAP ou recuit simulé |
|
|
|
|
10 |
Poids de timing HeAP : 10, 20, 30 ou 40. |
|
2 |
Exposant de criticité HeAP : 2, 3 ou 4. |
|
false |
Active le rip-up expérimental piloté par le timing. |
|
false |
Active les poids alternatifs de Router2. |
|
vide |
Arguments nextpnr avancés. Toute utilisation doit être enregistrée comme partie de l’expérience. |
|
|
Version OSS CAD Suite utilisée pour la synthèse. |
|
|
Version utilisée par nextpnr dans les jobs de routage. Elle peut être différente pour une comparaison contrôlée de versions. |
max_parallel et seeds_per_job sont indépendants. Pour N seeds, le
workflow crée environ ceil(N / seeds_per_job) jobs. Au plus
max_parallel jobs s’exécutent simultanément, tandis que les seeds d’un même
job sont routés en série. Avec 260 seeds et deux seeds par job, le workflow crée
130 jobs de routage.
Pourquoi deux seeds par job GitHub
Un seed peut parfois prendre beaucoup plus de temps que ses voisins. De grands groupes de seeds permettent à un tel retardataire de monopoliser un runner et de retarder plusieurs seeds derrière lui. De très petits groupes augmentent le coût du checkout, des artefacts et du démarrage des runners. La valeur par défaut de deux seeds par job est un compromis pratique qui localise les échecs.
La matrice utilise fail-fast: false afin qu’un groupe de routage défaillant
n’annule pas tous les autres groupes. C’est important pour la caractérisation :
un mauvais seed ne doit pas masquer les résultats utiles de seeds indépendants.
Architecture des jobs
Le workflow possède quatre rôles logiques : prepare, watch, route
et summarize.
Job |
Timeout |
Note |
|---|---|---|
|
90 min |
Synthèse, provenance, matrice et publication des entrées figées. |
|
360 min |
Collecteur live des artifacts. |
|
350 min |
Couvre tout le groupe de matrice et tous ses seeds traités en série. |
|
60 min |
Téléchargement, agrégation, contrôle de complétude et artifact final. |
Comme le timeout du job route couvre le groupe complet, une grande valeur
de seeds_per_job devient risquée si plusieurs seeds approchent leur watchdog.
prepare : figer l’expérience
Le job prepare valide les paramètres, installe/restaure la chaîne d’outils,
initialise les sous-modules requis, synthétise la cible une seule fois, enregistre
le SHA256 du netlist, les révisions Git et gitlinks, les versions des outils et
les paramètres du workflow, construit la matrice de seeds puis publie une archive
de routage figée.
Chaque job de routage vérifie ensuite le SHA256 avant nextpnr. Cela empêche deux runners de comparer accidentellement des netlists différents.
L’artifact d’entrée figé et les artifacts de groupes utilisent actuellement une rétention d’un jour. L’artifact final résumé est conservé 14 jours ; archivez-le ailleurs lorsqu’il devient un point de contrôle durable du projet.
route : runners indépendants
Chaque job de matrice dispose de son propre runner Ubuntu. Les runners ne
partagent pas de système de fichiers. Le job télécharge donc l’archive figée,
restaure la version de nextpnr demandée, puis route ses seeds en série avec
SWEEP_JOBS=1 et SWEEP_SKIP_SYNTH=1.
Pour chaque seed, le job conserve la sortie console, les logs de routage, le CSV de résultat, le temps écoulé, le code de sortie, le SHA256 du netlist et, optionnellement, le bitstream.
watch : moniteur de timing en direct
Le moniteur en direct ne peut pas lire directement les autres runners GitHub.
Les groupes terminés publient donc de petits artifacts. Le job watch observe
ces artifacts et affiche les nouveaux résultats pendant que le routage continue.
./scripts/watch-ecp5-sweep-results.sh \
"${SWEEP_TARGET}" \
"${SWEEP_SEED_FIRST}" \
"${SWEEP_SEED_LAST}" \
"${SWEEP_SEEDS_PER_JOB}"
Exemple :
------------------------------------------------------------
LIVE TIMING RESULTS
Timing-passing seeds: 16 19 49
Progress: 22/260 seeds | 11/130 groups | 11/130 jobs
Status: PASS=3 FAIL=19 TIMEOUT=0 OTHER=0
PASS route duration: avg=388s | fastest=254s (seed 19) | slowest=582s (seed 49)
Best PASS max MHz: sys=51.27 (seed 19) | video=81.07 (seed 19) | tmds=370.78 (seed 19)
Timeout seeds: none
Other/problem seeds: none
------------------------------------------------------------
Les artifacts peuvent arriver dans le désordre. Les métriques mises en évidence
sont volontairement limitées aux seeds PASS. PASS route duration exclut
FAIL, TIMEOUT et OTHER : un seed arrêté par le watchdog ne peut donc pas devenir
le « slowest » route réussi. Best PASS max MHz calcule chaque maximum
uniquement parmi les seeds qui satisfont déjà toutes les contraintes. Les lignes
de groupe conservent les résultats FAIL et timeout comme références de diagnostic.
summarize : résultat final
Le job final télécharge tous les groupes et les références figées.
scripts/summarize-ecp5-sweep.py génère les résumés Markdown/CSV, l’inventaire
et les sommes SHA256, puis vérifie que chaque seed demandé possède un résultat ou
une classification explicite d’échec/timeout.
Timeouts
Le workflow courant protège les routages longs avec les limites suivantes :
Limite |
Valeur |
Rôle |
|---|---|---|
Timeout de routage |
7200 s |
Limite le routage nextpnr interne. |
Kill-after de routage |
30 s |
Escalade si le processus ne se termine pas. |
Timeout du seed complet |
7600 s |
Encadre l’invocation complète du sweep pour un seed. |
Kill-after du seed |
30 s |
Escalade l’arrêt d’un seed bloqué. |
Timeout du job GitHub de routage |
350 min |
Limite le job de matrice complet. |
Les codes 124 et 137 du watchdog sont enregistrés comme timeout et le job passe au seed suivant. Une autre erreur inattendue reste un problème d’outil ou d’intégration et doit rester visible.
Stratégie de sélection des paramètres
Pour un nouveau netlist :
Établissez une base avec les seeds 1-32 et HeAP/Router1.
Répétez exactement les mêmes seeds pour chaque comparaison contrôlée.
Étendez la ou les meilleures configurations à 1-128.
Ne lancez 1-260 que lorsque la configuration mérite le coût de calcul ou lorsqu’une distribution large est nécessaire.
Testez les poids/exposants HeAP, tmg_ripup et Router2 comme des expériences,
pas comme des améliorations garanties. Pour SA, utilisez un petit sous-ensemble
avec les timeouts actifs.
Si vous comparez des versions de nextpnr, conservez le netlist synthétisé et ne
changez que route_oss_cad_suite_version. Si la synthèse change, le SHA256 du
netlist change également et les anciens classements de seeds ne sont plus
directement comparables.
Interprétation et reproductibilité
PASS signifie que toutes les horloges requises passent. FAIL signifie
que le routage s’est terminé mais qu’au moins une horloge a raté sa contrainte.
Un timeout n’est pas une mesure de timing. NO_RESULT ou ERROR signale un
problème à diagnostiquer dans les logs.
Avant de comparer deux sweeps, vérifiez le SHA256 du netlist, la cible, les horloges, le profil de fonctionnalités, le coeur LiteDRAM, les contraintes, la version de nextpnr, les paramètres du placer/router et l’ensemble de seeds.
Après une modification d’un coeur généré, par exemple une nouvelle géométrie de mémoire LiteDRAM, resynthétisez et établissez une nouvelle base de seeds.
Liste de contrôle de reproductibilité
Avant de comparer deux sweeps, vérifiez tous les éléments suivants :
même SHA256 de la netlist synthétisée, sauf si la synthèse est la variable testée ;
même cible et même profil de fonctions propre à la cible ;
mêmes exigences d’horloge ;
même CPU/cœur LiteDRAM généré pour ULX4M-LD ;
même LPF/contraintes ;
même version de nextpnr utilisée pour le routage ;
mêmes réglages du placeur/routeur et mêmes arguments supplémentaires ; et
même sous-ensemble de seeds pour les comparaisons A/B contrôlées.
Après un changement de cœur généré, tel qu’une modification de périphérique/géométrie LiteDRAM, resynthétisez et établissez une nouvelle référence de seeds. Le classement des anciens seeds n’est pas transférable à la nouvelle netlist.
Conseils développeur et pièges courants
N’interprétez pas
--timing-allow-failcomme une dérogation ou un PASS de timing. Cette option permet seulement au routage de se terminer afin que le sweep collecte les valeurs de timing en échec.Ne choisissez pas un seed à partir du maximum d’une seule horloge sauf si ce même seed satisfait tous les domaines requis.
N’utilisez pas
SWEEP_SKIP_SYNTH=1après un changement de RTL, de cœur généré, d’horloge ou de contraintes sauf si la netlist correspondante a été volontairement régénérée.Gardez
seeds_per_jobfaible lorsque certains seeds présentent de longues durées extrêmes. Un grand groupe série peut transformer un seed pathologique en retard de plusieurs heures.max_parallelest une limite de concurrence des runners GitHub, pas le nombre de processus nextpnr à l’intérieur d’un job de routage. Chaque job route intentionnellement un seed à la fois.Des valeurs locales élevées de
SWEEP_JOBSpeuvent épuiser la mémoire avant que l’utilisation CPU paraisse saturée.Ne conservez les bitstreams que lorsque cela est utile. Les journaux de timing et CSV sont bien plus petits et suffisent pour la plupart des explorations.
Testez sur matériel le candidat de production choisi. La fermeture du timing statique est une preuve nécessaire, mais la qualification au niveau de la carte reste indispensable.
Conservez les artefacts finaux du sweep lorsqu’un résultat devient un point de contrôle du projet ; ils contiennent les hashes, la configuration, les versions d’outils et les preuves par seed nécessaires pour reproduire ou auditer le résultat plus tard.
Fichiers associés
.github/workflows/ulx4m-ld-seed-sweep.yml
scripts/sweep-ecp5.sh
scripts/sweep-ecp5-common.sh
scripts/sweep-ulx3s-85f.sh
scripts/sweep-ulx3s-12f.sh
scripts/sweep-ulx4m-ld.sh
scripts/watch-ecp5-sweep-results.sh
scripts/summarize-ecp5-sweep.py
Voir aussi Référence des scripts et Profils de cartes.
WHOLE_SEED_TIMEOUTou un autre état de timeoutLe watchdog a arrêté un routage qui a dépassé le temps autorisé. Ce n’est pas une mesure de timing et ce résultat ne doit pas être classé avec les routages terminés.