Zurück zur Startseite

SD-Karte als ROM für RISC-V YRV FPGA

Der Artikel beschreibt die Verwendung einer SD-Karte als Speicher für ausführbaren Code für den RISC-V YRV-Kern auf dem Tang Nano 9K-Board. Implementierte FSM zum Lesen von 512-Byte-Sektoren mit Caching im RAM. Tests mit HELO-Ausgabe bestätigen die Funktionalität.

SD statt RAM: RISC-V YRV auf FPGA mit Speicherkarte
Advertisement 728x90

SD-Karte als Code-Speicher für RISC-V YRV auf dem Tang-Nano-9K-FPGA

Auf kostengünstigen FPGA-Boards wie dem Tang Nano 9K sind die Syntheseressourcen begrenzt – insbesondere der On-Chip-Speicher (Block RAM) reicht nicht aus, um kompletten Programmcode zu speichern. Lediglich 16–20 KB stehen für Stack und Daten zur Verfügung: ausreichend für Basis-Tests, aber nicht für vollständige Firmware. Dieser Artikel stellt eine Lösung vor, bei der eine SD-Karte als externer, nur lesbarer Speicher (ROM) dient – mit sektorbasierter Lesezugriff auf jeweils 512 Byte. Funktionell ähnelt das dem eXecute-In-Place-Verfahren (XIP) von QSPI-Flash, ist jedoch an die Einschränkungen des SPI-Protokolls angepasst.

Der YRV-Core kommuniziert über einen 16-Bit-Datenbus mit dem Speicher. Die Lese-/Schreiblogik ist in Verilog implementiert:

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

Zustandsautomat für SD-Sektor-Caching

Der RAM wird auf genau 512 Byte reduziert – also genau einen Sektor. Wenn die CPU auf eine Adresse innerhalb des aktuell zwischengespeicherten Sektors zugreift, läuft die Ausführung unmittelbar weiter, wobei mem_ready gesetzt wird (analog zu HREADY im AHB-Lite-Protokoll). Bei einem Cache-Miss – also beim Zugriff außerhalb des aktuellen Sektors – löst der endliche Zustandsautomat (FSM) einen neuen Sektor-Lesevorgang von der SD-Karte aus. Ein Zähler byte_cnt verfolgt den Fortschritt des Lesevorgangs.

Google AdInline article slot

Der FSM umfasst drei Zustände:

  • IDLE: Wartet auf eine Speicherzugriffsanforderung.
  • READ: Liest den angeforderten 512-Byte-Sektor von der SD-Karte.
  • START: Initiiert den Lesebefehl (sendet rd).

Der SD-Controller basiert auf Open-Source-Projekten wie FPGA-SDcard-Reader und dem MIT 6.111-Kurs – und wurde anschließend für die SPI-Schnittstelle des Tang Nano 9K adaptiert (die Leitungen DAT1/DAT2 bleiben unverbunden). Die Initialisierung erfolgt mit 400 kHz für maximale Robustheit – ein Neustart per Stromzyklus ist nicht erforderlich.

Integration in das YRV-Plus-Projekt

Implementiert im Pfad labs/99_experimental/99_03_yrv_sd, aufbauend auf der Basis basics-graphics-music. Die Konfiguration tang_nano_9k_tm1638_sd legt die SD-Pins auf 3,3 V fest. Die Ausgabe nutzt den TM1638-Treiber: port0 steuert die BCD-Segmente; port1 wählt die Stelle des 7-Segment-Anzeigers.

Google AdInline article slot

Beispiel-Assemblercode zum Anzeigen von „HELO“ (jedes Zeichen liegt in einem eigenen Sektor):

li s0, 0xFFFF0000    # port0 — Segmentdaten
li s1, 0xFFFF0002    # port1 — Stellenauswahl

main_loop:
  # 'H' (Stelle 3)
  li t1, 0x8
  sh t1, 0(s1)
  .rept 100
  nop
  .endr
  li t2, 0b00110111
  sh t2, 0(s0)
  .rept 1000
  nop
  .endr
  # Analog für E, L, O wiederholen

Die Firmware wird sektorweise mit HxD geschrieben.

Testergebnisse:

Google AdInline article slot
  • Zwischen den Zeichen werden ca. 1.000 NOPs ausgeführt (repräsentiert realistische Rechenlast).
  • „HELO“ wird klar auf vier 7-Segment-Anzeigern dargestellt.
  • Zuverlässiger Reset und Start – kein Stromzyklus nötig.
  • Entfernen der SD-Karte führt zu sauberem Abbruch der Ausführung.

Kernpunkte

  • SD-Karten im SPI-Modus ermöglichen XIP-ähnliche Ausführung, wenn sie mit einem 512-Byte-Sektor-Cache kombiniert werden.
  • Der Zustandsautomat minimiert Latenz; mem_ready hält die CPU während Lesevorgängen synchron.
  • Ideal für Anwendungen mit geringer Bandbreite, bei denen Signal-Zeitverzögerungen im Millisekundenbereich liegen.
  • Für flüssigere Performance empfiehlt sich eine Cache-Erweiterung auf 1–2 KB.
  • Vollständig kompatibel mit YRV-Cores auf Gowin-FPGAs – sogar ohne externen SRAM.

Optimierungsmöglichkeiten

Die aktuelle Implementierung benötigt 6+ Taktzyklen pro Sektor-Lesevorgang (im Vergleich zu ebenfalls 6 bei QSPI). Eine Erweiterung des Caches auf 2–4 Sektoren würde Cache-Misses deutlich reduzieren. Auch ein Mehrbank-Buffering – analog zur ursprünglichen Speicherlogik des YRV – ist technisch machbar. Für fortgeschrittene Entwickler: Integration über Wishbone- oder AXI-Adapter ermöglicht den Einsatz dieser Lösung in größeren SoC-Architekturen.

— Editorial Team

Advertisement 728x90

Weiterlesen