Builds FPGA Tiny Tapeout sur ULX3S
Hazard3-Doom contient également un petit projet compatible Tiny Tapeout utilisé
comme test de fumée pour le flux FPGA Tiny Tapeout sur ULX3S. Ce flux est séparé
du build FPGA Hazard3-Doom normal : le flux Tiny Tapeout encapsule un module
utilisateur tt_um_* dans un top level spécifique à l’ULX3S et construit ce
module pour le FPGA ECP5. Il ne synthétise pas le CPU Hazard3 complet, le
contrôleur SDRAM, le framebuffer HDMI, le moniteur résident et l’application
Doom.
La prise en charge Tiny Tapeout pour ULX3S est actuellement développée dans les
branches experimental de ces forks maintenus par ULX3S :
ulx3s/tt-gds-action fournit l’Action GitHub réutilisable utilisée par le workflow d’un projet Tiny Tapeout.
ulx3s/tt-support-tools contient l’outil Python de build FPGA, le wrapper ULX3S et les contraintes LPF ULX3S.
État de la branche expérimentale
Les exemples de cette page utilisent volontairement @experimental. Ne
les remplacez pas par @main uniquement pour rendre le workflow plus
conventionnel. La prise en charge ULX3S est encore en cours d’intégration.
Lorsque les dépôts ULX3S publieront cette prise en charge sur une branche ou
un tag stable, mettez à jour ensemble les références de l’action et des
support-tools afin que le wrapper, l’interface en ligne de commande et le
workflow restent compatibles.
Rôle des deux dépôts
Les deux dépôts ont des fonctions différentes.
ulx3s/tt-gds-actionC’est le point d’entrée GitHub Actions. L’action composite ULX3S est
fpga/ulx3s/action.yml. Elle récupère les outils de support, installe leurs dépendances Python, crée la configuration utilisateur Tiny Tapeout, installe une version épinglée d’OSS CAD Suite, exécute l’étape de hardening FPGA ECP5, puis téléverse les fichiers de build produits comme artifact du workflow.ulx3s/tt-support-toolsC’est ici que se trouve l’implémentation du build FPGA.
tt_fpga.pylit les métadonnées du projet Tiny Tapeout, génère un wrapper spécifique à la carte, exécute Yosys, nextpnr-ecp5 et ecppack, puis écrit le bitstream ECP5 et les logs produits sousbuild/.
Cette séparation est utile pour le diagnostic. Un problème de workflow/YAML se situe normalement dans la couche action ; un problème de synthèse, de wrapper, de mapping des broches, de périphérique ECP5 ou de placement-routage se situe normalement dans la couche support-tools.
Structure requise du projet Tiny Tapeout
Le flux attend la structure habituelle des métadonnées et sources d’un projet Tiny Tapeout. Dans Hazard3-Doom, les fichiers concernés sont :
info.yaml
src/
config.json
project.v
info.yaml est particulièrement important. Il fournit le nom top_module
et la liste des fichiers source Verilog. Le module supérieur doit utiliser
l’interface Tiny Tapeout tt_um_*. Hazard3-Doom utilise actuellement le petit
module de test de fumée tt_um_ulx3s_example dans src/project.v.
Le builder FPGA peut être utilisé sans info.yaml en fournissant manuellement
les options de source et de module supérieur, mais le workflow du dépôt utilise
volontairement les métadonnées Tiny Tapeout standard afin que la même
description de projet reste utile pour les flux ASIC et FPGA.
Workflow GitHub Actions
Le job ULX3S utilisé par Hazard3-Doom est :
fpga-ulx3s:
runs-on: ubuntu-24.04
steps:
- name: checkout repo
uses: actions/checkout@v7
with:
submodules: recursive
- name: FPGA bitstream for TT ASIC Sim (ULX3S ECP5)
uses: ulx3s/tt-gds-action/fpga/ulx3s@experimental
with:
ecp5-device: 85k
lpf: tt/fpga/ulx3s/ulx3s_v20.lpf
artifact-name: fpga_ulx3s_ecp5
uart-enabled: true
Ce job peut être placé à côté du job FPGA Tiny Tapeout habituel. Le workflow
Hazard3-Doom actuel construit également la cible iCE40 UP5K avec l’action
fpga/ice40up5k correspondante, de sorte que le même projet TT est testé au
travers de deux implémentations FPGA.
Pourquoi utiliser un checkout récursif
submodules: recursive récupère le projet exactement tel qu’il est représenté
par le dépôt, y compris les dépendances source représentées par des sous-modules
Git. L’action ULX3S effectue ensuite son propre checkout de tt-support-tools
dans un répertoire de travail nommé tt. Il s’agit de deux checkouts distincts :
le premier checkout est le projet Tiny Tapeout à construire ;
le second checkout fournit les outils de build Tiny Tapeout.
Entrées de l’action
ecp5-deviceSélectionne la densité ECP5 transmise à
tt_fpga.pypuis à nextpnr-ecp5. Hazard3-Doom utilise85kpour la carte ULX3S 85F. L’outil de support actuel accepte12k,25k,45ket85kpour les cibles ECP5.lpfChemin vers le Lattice Preference File contenant les contraintes physiques de broches et d’horloge de l’ULX3S. Hazard3-Doom sélectionne explicitement
tt/fpga/ulx3s/ulx3s_v20.lpfpour ce workflow. L’action ULX3S réutilisable utilise actuellementulx3s_v316.lpfpar défaut ; conserver le LPF explicite évite donc de changer silencieusement les contraintes de la carte si la valeur par défaut de l’action évolue. Le fichier v20 sélectionné associeclk_25mhzà l’oscillateur de la carte, contraint ce port à 25 MHz et mappe les LED, boutons, GPIO et autres signaux utilisés par le wrapper.artifact-nameNom de base de l’artifact GitHub Actions. L’action ajoute le périphérique ECP5 sélectionné ; l’exemple produit donc un artifact nommé
fpga_ulx3s_ecp5_85k.uart-enabledLorsque cette valeur est
true, l’action transmet la définition VerilogUART_ENABLEDau build FPGA. Cela active le mapping UART optionnel du wrapper ULX3S. Utilisezfalsepour un projet qui ne souhaite pas ce mapping.
L’action composite possède aussi les entrées tools-repo et tools-ref.
Leurs valeurs par défaut actuelles sont ulx3s/tt-support-tools et
experimental. Elles sont normalement laissées telles quelles afin que
l’action utilise la branche support-tools ULX3S correspondante, mais elles sont
utiles pour tester un fork de développement ou un commit précis.
Ce que l’action exécute
L’action composite ULX3S actuelle effectue les opérations suivantes :
Checkout de
ulx3s/tt-support-toolsà la référencetools-refdemandée danstt/.Configuration de Python 3.11 et installation de
tt/requirements.txt.Si le projet contient
test/requirements.txt, installation de ces dépendances également.Exécution de
tt/tt_tool.py --create-user-configafin que les outils de support connaissent le module supérieur et la configuration des sources du projet.Installation d’OSS CAD Suite avec
YosysHQ/setup-oss-cad-suite@v4. L’action expérimentale actuelle épingle la version de la suite à2026-04-26.Exécution de l’équivalent de la commande de build ULX3S suivante :
python tt/tt_fpga.py harden \ --name tt_um_fpga_ecp5_85k \ --fpga-target ulx3s-ecp5 \ --ecp5-device 85k \ --lpf tt/fpga/ulx3s/ulx3s_v20.lpf \ --define UART_ENABLED
Téléversement des produits de build et des fichiers de projet associés comme artifact GitHub Actions, même si une étape ultérieure signale un échec.
L’argument --define UART_ENABLED n’est inclus que lorsque
uart-enabled: true.
À l’intérieur de tt_fpga.py
Pour la cible ulx3s-ecp5, tt_fpga.py génère src/_tt_fpga_top.v à
partir du template support-tools fpga/ulx3s/tt_fpga_top_ulx3s.v. Le module
utilisateur fictif présent dans ce template est remplacé par le top_module
de info.yaml.
Le wrapper généré est ensuite synthétisé avec les sources du projet. Le flux ECP5 est conceptuellement :
info.yaml + src/project.v
|
v
generate src/_tt_fpga_top.v
|
v
Yosys synth_ecp5
|
v
build/<name>.json
|
v
nextpnr-ecp5
|
v
build/<name>.config
|
v
ecppack
|
v
build/<name>.bit
Pour l’exemple de workflow, les fichiers importants sont normalement :
build/01-synth.log
build/02-nextpnr.log
build/tt_um_fpga_ecp5_85k.json
build/tt_um_fpga_ecp5_85k.config
build/tt_um_fpga_ecp5_85k.bit
01-synth.log est le premier endroit à consulter pour les problèmes HDL, de
module ou de synthèse. 02-nextpnr.log contient l’utilisation du périphérique,
les informations de placement/routage et le timing. Le fichier .bit est le
bitstream ECP5 destiné à l’ULX3S.
Comportement du wrapper ULX3S
Le wrapper actuel fournit volontairement un environnement de test Tiny Tapeout simple et observable :
l’oscillateur ULX3S
clk_25mhzpilote l’entrée Tiny Tapeoutclk;le bouton 0 de l’ULX3S pilote l’entrée Tiny Tapeout active-bas
rst_n;Tiny Tapeout
enaest maintenu à l’état haut ;uo_out[7:0]est connecté aux huit LED de l’ULX3S ;lorsque
UART_ENABLEDest défini,gp0de l’ULX3S est synchronisé et mappé vers Tiny Tapeoutui_in[3];lorsque
UART_ENABLEDest défini, Tiny Tapeoutuo_out[4]pilotegp1de l’ULX3S comme chemin de transmission UART ;uio_inest maintenu à zéro par ce wrapper, même si le projet expose toujours l’interface Tiny Tapeout normaleuio_outetuio_oe.
Ce mapping permet de tester directement un projet TT simple avec les LED, les boutons et l’UART avant de passer au hardening ASIC ou à une navette physique.
Exécuter le même flux ULX3S localement
L’Action GitHub est le chemin reproductible le plus simple, mais les mêmes outils de support peuvent être exécutés localement. Depuis la racine d’un projet Tiny Tapeout :
git clone --branch experimental \
https://github.com/ulx3s/tt-support-tools.git tt
python3 -m pip install -r tt/requirements.txt
python3 tt/tt_tool.py --create-user-config
Yosys, nextpnr-ecp5, Project Trellis/ecppack et leurs données de
périphériques ECP5 doivent également être disponibles dans PATH. L’Action
GitHub les fournit via sa configuration OSS CAD Suite épinglée ; un build local
peut utiliser une installation OSS CAD Suite équivalente.
Exécutez ensuite explicitement le même build FPGA :
python3 tt/tt_fpga.py harden \
--name tt_um_fpga_ecp5_85k \
--fpga-target ulx3s-ecp5 \
--ecp5-device 85k \
--lpf tt/fpga/ulx3s/ulx3s_v20.lpf \
--define UART_ENABLED
Omettez --define UART_ENABLED pour construire sans le mapping UART
optionnel.
L’outil de support accepte également les variables d’environnement
TT_FPGA_SEED et TT_FPGA_FREQ, qui sont transmises au flux de
placement-routage. Pour une validation normale du projet, utilisez d’abord les
valeurs par défaut du workflow pris en charge au lieu de modifier arbitrairement
les paramètres de routage ; si un projet nécessite un seed ou une cible de
timing différente, consignez ces réglages avec les résultats du test.
Programmer le bitstream généré
Le fichier .bit local ou téléchargé est un bitstream ECP5 ULX3S normal.
Avec une installation fujprog compatible, un chargement volatil du FPGA
peut être effectué avec :
fujprog build/tt_um_fpga_ecp5_85k.bit
La configuration SRAM du FPGA est perdue lorsque l’alimentation de la carte est coupée. C’est généralement le comportement souhaité pour un test de fumée Tiny Tapeout, car il ne remplace pas une image flash persistante. Voir Programmation et démarrage persistant et Flasher FPGA WebUSB pour les méthodes de programmation Hazard3-Doom et les considérations liées aux pilotes USB.
Ne confondez pas tt_fpga.py harden avec
tt_fpga.py configure --upload. La sous-commande configure actuelle fait
partie du chemin de configuration base de données/breakout Tiny Tapeout et
recherche une image .bin. Le build ECP5 ULX3S décrit ici produit un fichier
.bit ; programmez ce bitstream ECP5 avec un outil de programmation FPGA
ULX3S.
Télécharger et vérifier l’artifact GitHub
Après la fin du job fpga-ulx3s, ouvrez l’exécution du workflow et
téléchargez l’artifact fpga_ulx3s_ecp5_85k. L’action est configurée pour
inclure le répertoire build/ ainsi que docs/, src/, info.yaml,
LICENSE et le fichier LPF sélectionné. L’artifact est ainsi utile à la fois
pour programmer la carte et pour diagnostiquer précisément ce qui a été
construit.
Pour un build réussi, vérifiez au minimum :
build/tt_um_fpga_ecp5_85k.bitexiste et n’est pas vide ;build/01-synth.logmontre le module supérieur Tiny Tapeout attendu ;build/02-nextpnr.logidentifie le périphérique ECP5 prévu et ne contient aucun échec de routage ;le LPF présent dans l’artifact est bien le fichier de contraintes ULX3S attendu par le workflow ;
le log GitHub Actions montre les références attendues pour
ulx3s/tt-gds-actionetulx3s/tt-support-tools.
Dépannage
No project yaml, must specify ...Le builder n’a pas trouvé le fichier
info.yamlattendu à la racine du projet, ou la commande a été exécutée depuis le mauvais répertoire. Utilisez la racine normale du projet TT ou fournissez explicitement les options de source/module supérieur.ulx3s-ecp5 requires --lpf ...La cible ECP5 a besoin d’un fichier de contraintes physiques. Utilisez le LPF ULX3S correspondant depuis l’arborescence support-tools récupérée, sauf si vous testez volontairement une autre révision de carte ou un autre mapping de broches.
- Yosys ne trouve pas le module utilisateur
Vérifiez
top_moduledansinfo.yaml, la listesource_filesetbuild/01-synth.log. Inspectez également le fichier générésrc/_tt_fpga_top.vpour confirmer que le placeholder a été remplacé par le modulett_um_*attendu.- nextpnr signale des erreurs de broches ou de package
Confirmez que
ecp5-deviceet le LPF correspondent à la carte ULX3S réelle. Ne corrigez pas une incompatibilité de carte en supprimant des contraintes.- L’UART ne répond pas
Confirmez que
uart-enabled: truea été utilisé et rappelez-vous que le wrapper mappegp0versui_in[3]etuo_out[4]versgp1. Le module Tiny Tapeout lui-même doit implémenter le comportement de réception/transmission correspondant ; activer le wrapper n’ajoute pas de cœur UART au design utilisateur.- Le workflow fonctionne mais pas un build manuel
Comparez d’abord les versions des outils. L’Action GitHub épingle volontairement OSS CAD Suite et la branche support-tools
experimental. Une version locale différente de Yosys, nextpnr-ecp5 ou Project Trellis peut produire des résultats différents.