Das Titelbild dieses Blogbeitrags basiert auf einem Bild von Shawn Suttle auf Pixabay.
Was ist eine System View Description (SVD)? Wofür kann sie verwendet werden? Und gibt es eine Verbindung zu AVR-Mikrocontrollern?
Das sind viele Fragen, und dieses Mal findet man die Antwort nicht in der Wikipedia. Die maßgebliche Antwort darauf, was SVD ist, findest du auf dieser Website. Es ist ein XML-Format, das im ARM-Ökosystem entwickelt wurde, um Computer zu beschreiben. Die Idee ist, ein maschinenlesbares Format zu haben, das eine CPU und ihre Peripherieregister beschreibt und das zur Ableitung von Header-Dateien, zur Information von Debugger-GUIs und vielem mehr verwendet werden kann.
Bis vor einer Woche war mir nicht bewusst, dass es so etwas gibt. Aber als ich den Arduino IDE 2 Debugger auf einem MKR Zero ausprobierte, fiel mir auf, dass das Debuggerfenster CORTEX PERIPHERALS eine Ansicht aller Register der MCU enthielt. Bei näherer Betrachtung stellte sich heraus, dass ein Verweis auf eine SVD-Datei eine solche Ansicht vermittelte.
Da ich zurzeit an der Implementierung eines GDB-Servers für AVR MCUs arbeite, um das Debugging in der Arduino IDE 2 und PlatformIO zu unterstützen, war ich neugierig, ob etwas Ähnliches auch für AVR MCUs möglich ist. Spoiler-Alarm: Ja, es ist möglich!
Zunächst einmal musst du SVD-Dateien für AVR MCUs besorgen. Aber wo bekommt man die? Die maschinenlesbaren AVR-Beschreibungen von Microchip sind ATDF-Dateien, die ebenfalls ein XML-Format verwenden, das sich aber von SVD unterscheidet. Eine Suche im Internet führt nicht zu einem SVD-Repository. Allerdings findet man auf GitHub ein in Rust geschriebenes Tool atdf2svd. Da sein Hauptzweck darin besteht, Rust-Header-Dateien zu erzeugen, macht diese Konvertierung einige Annahmen, die für den Anwendungsfall Debugger nicht gelten. Erstens werden der Stack-Zeiger und das Statusregister aus der Beschreibung entfernt, da sie aus Rust-Sicht unsicher sind. Zweitens enthält sie Fuses und Lockbits, die nicht wirklich notwendig sind. Außerdem wäre etwas mehr Arbeit nötig, um sie innerhalb des GDB-Servers zu implementieren.
Obwohl ich in Rust nicht wirklich programmieren kann, was die Untertreibung des Monats ist, konnte ich einen Pull-Request auf GitHub erstellen, damit die beiden Probleme behoben werden. Wenn man die Optionen -a keep_unsafe_cpu_registers und -a remove_fuse_and_lockbit angibt, werden Stackpointer und Statusregister einbezogen und Lockbits und Fuses entfernt. Bevor man die SVD-Dateien verwenden kann, muss man sie jedoch noch weiter bearbeiten.
Wenn du die SVD-Dateien in der Arduino IDE 2 so verwendest, wie sie von dem Konvertierungstool erzeugt werden, wirst du feststellen, dass zwar alle Registergruppen, Register und Bitfelder angezeigt werden, die Registerwerte aber alle konstant 0 sind. Der Grund dafür ist, dass das Feld baseAddress in den SVD-Dateien Datenadressen mit der Basisadresse 0x0000 verwendet. Der Debugger benötigt jedoch Adressen mit einer Basisadresse von 0x800000, um festzustellen, dass sich die Adressen auf den Datenbereich beziehen. Hier sind also Anpassungen erforderlich.
Außerdem stellt sich die Frage, was mit dem ATDF-Attribut ocd-rw="" geschehen soll. Dieses Attribut findet man sehr oft in Registerbeschreibungen des On-Chip-Debugger (OCD)-Registers und der seriellen I/O-Register. Es bedeutet wahrscheinlich, dass der Debugger nicht auf ein solches Register zugreifen darf. Wenn der Debugger aus dem OCD-Register liest, bekommt der Hardware-Debugger Schluckauf. Wenn der Debugger aus einem seriellen E/A-Register liest, wird die aktuelle Eingabe gelöscht. Das Schreiben hingegen ist unkritisch. Bei OCD-Registern scheint es ein No-op zu sein. Bei E/A-Registern kann man damit tatsächlich das nächste Ausgangsbyte in das Register schreiben. Aus diesen Gründen halte ich es für die beste Lösung, dem Debugger das Lesen solcher Register zu verbieten und dies in den SVD-Beschreibungen zu vermerken. Das bedeutet, dass die ATDF-Dateien gepatcht werden müssen, bevor sie konvertiert werden.
Bei der Durchsicht der ATDF-Dateien fällt auf, dass das ocd-rw-Attribut nicht ganz konsequent verwendet wird. Manchmal fehlt bei den UART- oder SPI-Registern die Markierung ocd-rw="", was man nachziehen kann. Bei der ATmegaC1- und ATmegaM1-Familie sind alle CAN-Bus- und alle PSC-Register mit ocd-rw="" gekennzeichnet, was nach dem Lesen der Registerbeschreibungen nicht sinnvoll erscheint. Also muss ein weiterer Patch angewendet werden.
Damit können die SVD-Dateien endlich ihre Arbeit beginnen.

Wie du sehen kannst, werden alle Registergruppen im linken Fenster angezeigt. Außerdem werden, wenn du eine der Registergruppen ausgewählt hast, die Änderungen gegenüber dem letzten Wert hervorgehoben, wie im Fall der PORTB-Register oben. Außerdem erhältst du Informationen zu jedem Register, wenn du mit dem Mauszeiger über dieses Register fährst, wie in der folgenden Abbildung gezeigt.

All das funktioniert auch, wenn du PlatformIO/VSC verwendest. Du musst nur die SVD-Datei in deinen Projektordner kopieren und die Zeile debug_svd_path=<mcu-name> in die Datei platformio.ini einfügen.
Was könnte man also noch tun? Wie sich herausstellte, haben die Rust-Leute eine Menge Patches für jede der AVR SVD-Dateien gesammelt, die ich in Zukunft überprüfen werde. Im Moment bin ich jedoch zufrieden, dass die Integration von SVD-Dateien in die Debugging-Umgebung bisher erfolgreich war. Und die SVDs machen das Debuggen auf Registerebene definitiv viel angenehmer.
Schreibe einen Kommentar