In vielen Anwendungen kann eine CPU, deren Befehlsausführung eine bekannte zeitliche Beziehung zu erwarteten Eingabestimuli aufweist, Aufgaben ausführen, die eine viel schnellere CPU erfordern würden, wenn die Beziehung unbekannt wäre. In einem Projekt, in dem ich ein PSOC zum Generieren von Videos verwendet habe, habe ich beispielsweise alle 16 CPU-Takte ein Byte Videodaten mit Code ausgegeben. Da das Testen, ob das SPI-Gerät bereit ist, und das Verzweigen, wenn nicht, 13 Takte dauern würde und das Laden und Speichern zum Ausgeben von Daten 11 Takte dauern würde, gab es keine Möglichkeit, das Gerät auf Bereitschaft zwischen Bytes zu testen. Stattdessen habe ich einfach dafür gesorgt, dass der Prozessor für jedes Byte nach dem ersten genau den Code von 16 Zyklen ausführt (ich glaube, ich habe eine echte indizierte Last, eine indizierte Dummy-Last und einen Speicher verwendet). Der erste SPI-Schreibvorgang für jede Zeile erfolgte vor dem Start des Videos. und für jedes nachfolgende Schreiben gab es ein 16-Zyklus-Fenster, in dem das Schreiben ohne Pufferüberlauf oder -unterlauf stattfinden konnte. Die Verzweigungsschleife erzeugte ein Unsicherheitsfenster mit 13 Zyklen, aber die vorhersagbare Ausführung mit 16 Zyklen bedeutete, dass die Unsicherheit für alle nachfolgenden Bytes in dasselbe Fenster mit 13 Zyklen passte (was wiederum in das 16-Zyklus-Fenster passte, in dem das Schreiben akzeptabel sein konnte auftreten).
Für ältere CPUs waren die Befehlszeitinformationen klar, verfügbar und eindeutig. Für neuere ARMs scheinen die Timing-Informationen viel vager zu sein. Ich verstehe, dass bei der Ausführung von Code aus dem Flash das Caching-Verhalten die Vorhersage erheblich erschweren kann. Daher würde ich davon ausgehen, dass Code mit Zykluszählung aus dem RAM ausgeführt werden sollte. Selbst wenn Code aus dem RAM ausgeführt wird, wirken die Spezifikationen etwas vage. Ist die Verwendung von zyklisch gezähltem Code immer noch eine gute Idee? Wenn ja, was sind die besten Techniken, damit es zuverlässig funktioniert? Inwieweit kann man mit Sicherheit davon ausgehen, dass ein Chiphersteller nicht stillschweigend in einen "neuen, verbesserten" Chip eintaucht, der in bestimmten Fällen die Ausführung bestimmter Anweisungen zyklisch verzögert?
Angenommen, die folgende Schleife beginnt an einer Wortgrenze, wie würde man anhand von Spezifikationen genau bestimmen, wie lange es dauern würde (angenommen, Cortex-M3 mit Null-Wartezustandsspeicher; für dieses Beispiel sollte nichts anderes über das System von Bedeutung sein).
myloop: mov r0, r0; Kurze einfache Anweisungen, um das Vorabrufen weiterer Anweisungen zu ermöglichen mov r0, r0; Kurze einfache Anweisungen, um das Vorabrufen weiterer Anweisungen zu ermöglichen mov r0, r0; Kurze einfache Anweisungen, um das Vorabrufen weiterer Anweisungen zu ermöglichen mov r0, r0; Kurze einfache Anweisungen, um das Vorabrufen weiterer Anweisungen zu ermöglichen mov r0, r0; Kurze einfache Anweisungen, um das Vorabrufen weiterer Anweisungen zu ermöglichen mov r0, r0; Kurze einfache Anweisungen, um das Vorabrufen weiterer Anweisungen zu ermöglichen fügt r2, r1, # 0x12000000 hinzu; 2-Wort-Anweisung ; Wiederholen Sie das Folgende, möglicherweise mit verschiedenen Operanden ; Addiert so lange Werte, bis ein Übertrag auftritt itcc Addscc r2, r2, # 0x12000000; 2-Wort-Anweisung plus zusätzliches "Wort" für itcc itcc Addscc r2, r2, # 0x12000000; 2-Wort-Anweisung plus zusätzliches "Wort" für itcc itcc Addscc r2, r2, # 0x12000000; 2-Wort-Anweisung plus zusätzliches "Wort" für itcc itcc Addscc r2, r2, # 0x12000000; 2-Wort-Anweisung plus zusätzliches "Wort" für itcc ; ... etc, mit mehr bedingten Zwei-Wort-Anweisungen Unter R8, R8, # 1 bpl myloop
Während der Ausführung der ersten sechs Befehle hätte der Kern Zeit, sechs Wörter abzurufen, von denen drei ausgeführt würden, so dass bis zu drei vorabgerufen werden könnten. Die nächsten Anweisungen bestehen aus jeweils drei Wörtern, so dass der Kern Anweisungen nicht so schnell abrufen kann, wie sie ausgeführt werden. Ich würde erwarten, dass einige der "it" -Anweisungen einen Zyklus benötigen, aber ich weiß nicht, wie ich vorhersagen soll, welche.
Es wäre schön, wenn ARM bestimmte Bedingungen spezifizieren könnte, unter denen das "it" -Befehls-Timing deterministisch wäre (z. B. wenn es keine Wartezustände oder Code-Bus-Konflikte gibt und die vorhergehenden zwei Befehle 16-Bit-Register-Befehle usw. sind). aber ich habe keine solche Spezifikation gesehen.
Beispielanwendung
Angenommen, man versucht, eine Tochterplatine für einen Atari 2600 zu entwerfen, um eine Komponentenvideoausgabe mit 480P zu generieren. Der 2600 verfügt über einen Pixeltakt von 3,579 MHz und einen CPU-Takt von 1,19 MHz (Punkttakt / 3). Für 480P-Komponentenvideo muss jede Zeile zweimal ausgegeben werden, was eine Punkttaktausgabe von 7,158 MHz impliziert. Da der Atari-Videochip (TIA) eine von 128 Farben mit einem 3-Bit-Lumasignal und einem Phasensignal mit einer Auflösung von ungefähr 18 ns ausgibt, ist es schwierig, die Farbe nur durch Betrachten der Ausgänge genau zu bestimmen. Ein besserer Ansatz wäre, Schreibvorgänge in die Farbregister abzufangen, die geschriebenen Werte zu beobachten und jedes Register in die TIA-Luminanzwerte einzuspeisen, die der Registernummer entsprechen.
All dies könnte mit einem FPGA durchgeführt werden, aber einige recht schnelle ARM-Geräte sind weitaus billiger als ein FPGA mit genügend RAM, um die erforderliche Pufferung zu bewältigen (ja, ich weiß, dass für die Volumes, die so etwas produzieren, die Kosten nicht hoch sind). t ein realer Faktor). Das Erfordernis, dass der ARM das eingehende Taktsignal überwacht, würde jedoch die erforderliche CPU-Geschwindigkeit erheblich erhöhen. Vorhersagbare Zykluszahlen könnten die Dinge sauberer machen.
Ein relativ einfacher Entwurfsansatz besteht darin, dass eine CPLD die CPU und den TIA überwacht und ein 13-Bit-RGB + -Synchronsignal erzeugt und dann ARM-DMA 16-Bit-Werte von einem Port abruft und sie mit dem richtigen Timing in einen anderen schreibt. Es wäre jedoch eine interessante Designherausforderung, zu sehen, ob ein billiger ARM alles kann. DMA könnte ein nützlicher Aspekt eines All-in-One-Ansatzes sein, wenn seine Auswirkungen auf die CPU-Zykluszahlen vorhergesagt werden könnten (insbesondere, wenn die DMA-Zyklen in Zyklen auftreten könnten, in denen der Speicherbus ansonsten inaktiv war), aber zu einem bestimmten Zeitpunkt im Prozess Der ARM müsste seine Funktionen zur Tabellensuche und Busüberwachung ausführen. Beachten Sie, dass der Atari 2600 im Gegensatz zu vielen Videoarchitekturen, bei denen Farbregister während der Austastintervalle geschrieben werden, während des angezeigten Teils eines Frames häufig in Farbregister schreibt.
Vielleicht wäre der beste Ansatz, ein paar diskrete Logikchips zu verwenden, um Farbschreibvorgänge zu identifizieren und die unteren Bits der Farbregister auf die richtigen Werte zu zwingen, und dann zwei DMA-Kanäle zu verwenden, um die eingehenden CPU-Bus- und TIA-Ausgangsdaten abzutasten, und einen dritten DMA-Kanal zum Erzeugen der Ausgangsdaten. Die CPU kann dann alle Daten von beiden Quellen für jede Abtastzeile verarbeiten, die erforderliche Übersetzung durchführen und für die Ausgabe puffern. Der einzige Aspekt der Aufgaben des Adapters, der in "Echtzeit" erfolgen müsste, wäre das Überschreiben von Daten, die in COLUxx geschrieben wurden, und dies könnte unter Verwendung von zwei gemeinsamen Logik-Chips erledigt werden.