Utiliser une carte SD comme mémoire de stockage pour le cœur RISC-V YRV sur FPGA Tang Nano 9K
Sur les cartes FPGA abordables comme la Tang Nano 9K, les ressources de synthèse limitées restreignent la RAM embarquée — ce qui rend peu pratique le stockage intégral du code programme dans la mémoire bloc. Seulement 16 à 20 Ko sont disponibles pour la pile et les données : suffisant pour des tests basiques, mais insuffisant pour un micrologiciel complet. Cet article propose d’utiliser une carte SD comme mémoire morte externe (ROM) en lecture seule, avec des lectures par secteur de 512 octets — fonctionnellement similaire à l’exécution directe depuis une mémoire QSPI (XIP), mais adaptée aux contraintes du protocole SPI.
Le cœur YRV interagit avec la mémoire via un bus 16 bits. La logique de lecture/écriture est implémentée en Verilog :
always @ (posedge clk) begin
if (mem_trans[0]) begin
mem_rdata[31:24] <= mcu_mem_bank3 [mem_addr[13:2]];
mem_rdata[23:16] <= mcu_mem_bank2 [mem_addr[13:2]];
mem_rdata[15:8] <= mcu_mem_bank1 [mem_addr[13:2]];
mem_rdata[7:0] <= mcu_mem_bank0 [mem_addr[13:2]];
end
if (mem_wr_byte[3]) mcu_mem_bank3 [mem_addr_reg[13:2]] <= mem_wdata[31:24];
if (mem_wr_byte[2]) mcu_mem_bank2 [mem_addr_reg[13:2]] <= mem_wdata[23:16];
if (mem_wr_byte[1]) mcu_mem_bank1 [mem_addr_reg[13:2]] <= mem_wdata[15:8];
if (mem_wr_byte[0]) mcu_mem_bank0 [mem_addr_reg[13:2]] <= mem_wdata[7:0];
end
Machine à états pour la mise en cache des secteurs SD
La RAM est réduite à 512 octets exactement — soit un seul secteur. Lorsque le processeur accède à une adresse située dans le secteur actuellement mis en cache, l’exécution se poursuit immédiatement avec mem_ready validé (équivalent fonctionnel de HREADY dans AHB-Lite). En cas de défaut de cache — c’est-à-dire lors d’un accès hors du secteur courant — la machine à états finie (FSM) déclenche une nouvelle lecture de secteur depuis la carte SD. Un compteur byte_cnt suit l’avancement de la lecture.
La FSM comporte trois états :
- IDLE : attend une requête d’accès mémoire.
- READ : lit le secteur demandé de 512 octets depuis la carte SD.
- START : lance la commande de lecture (envoie
rd).
Le contrôleur SD s’inspire de projets open source comme FPGA-SDcard-Reader et MIT 6.111, puis a été adapté à l’interface SPI de la Tang Nano 9K (les lignes DAT1/DAT2 restent non connectées). L’initialisation s’effectue à 400 kHz pour plus de robustesse — aucun redémarrage ou réinitialisation matérielle n’est requis.
Intégration dans le projet YRV Plus
Implémenté dans labs/99_experimental/99_03_yrv_sd, construit sur la base basics-graphics-music. La configuration tang_nano_9k_tm1638_sd assigne les broches SD à 3,3 V. La sortie utilise le contrôleur TM1638 : port0 pilote les segments BCD ; port1 sélectionne la position du chiffre.
Exemple de code assembleur pour afficher « HELO » (chaque caractère stocké dans un secteur distinct) :
li s0, 0xFFFF0000 # port0 — données des segments
li s1, 0xFFFF0002 # port1 — position du chiffre
main_loop:
# 'H' (chiffre 3)
li t1, 0x8
sh t1, 0(s1)
.rept 100
nop
.endr
li t2, 0b00110111
sh t2, 0(s0)
.rept 1000
nop
.endr
# Répéter de façon similaire pour E, L, O
Le micrologiciel est écrit secteur par secteur à l’aide de HxD.
Résultats des tests :
- Environ 1 000 instructions NOP exécutées entre chaque caractère (représentant une charge utile réelle).
- « HELO » s’affiche clairement sur quatre chiffres à sept segments.
- Réinitialisation et démarrage fiables — aucune coupure d’alimentation nécessaire.
- Le retrait de la carte SD arrête proprement l’exécution.
Points clés à retenir
- Les cartes SD en mode SPI permettent une exécution XIP-like lorsqu’elles sont couplées à un cache de secteur de 512 octets.
- La FSM minimise la latence ;
mem_readymaintient le processeur synchronisé pendant les lectures. - Idéal pour les applications à faible débit où les délais de signal sont de l’ordre de la milliseconde.
- Pour de meilleures performances, envisagez d’augmenter la taille du cache à 1–2 Ko.
- Entièrement compatible avec les cœurs YRV sur FPGA Gowin — même sans SRAM externe.
Pistes d’optimisation
L’implémentation actuelle nécessite plus de 6 cycles d’horloge par lecture de secteur (contre 6 pour QSPI). Passer à un cache de 2 à 4 secteurs réduirait fortement le nombre de défauts de cache. Une mise en mémoire tampon multi-banque — calquée sur la logique mémoire originale de YRV — est également envisageable. Pour les développeurs avancés : une intégration avec des interfaces Wishbone ou AXI permettrait d’étendre cette solution à des conceptions SoC plus complexes.
— Editorial Team
Aucun commentaire pour le moment.