Über Codedichte und ihre Definition

Ich habe eine konzeptionelle Frage: Was bedeutet "hohe" Codedichte? und warum ist es so wichtig?

Antworten (2)

Die Codedichte bezieht sich grob darauf, wie viele Mikroprozessoranweisungen erforderlich sind, um eine angeforderte Aktion auszuführen, und wie viel Platz jede Anweisung einnimmt. Allgemein gesagt, je weniger Platz eine Anweisung einnimmt und je mehr Arbeit pro Anweisung ein Mikroprozessor leisten kann, desto dichter ist sein Code.

Mir ist aufgefallen, dass Sie Ihre Frage mit dem Tag „Arm“ gekennzeichnet haben. Ich kann die Codedichte mit ARM-Anweisungen veranschaulichen.

Angenommen, Sie möchten einen Datenblock von einer Speicherstelle an eine andere kopieren. Konzeptionell würde Ihr High-Level-Code etwa so aussehen:

void memcpy(void *dest, void *source, int count_bytes)
{
    char *s, *d;

    s = source; d = dest;
    while(count_bytes--) { *d++ = *s++; }
}

Nun kann ein einfacher Compiler für einen einfachen Mikroprozessor dies in etwa wie folgt umwandeln:

movl r0, count_bytes
movl r1, s
movl r2, d
loop: ldrb r3, [r1]
strb [r2], r3
movl r3, 1
add r1, r3
add r2, r3
sub r0, r3
cmp r0, 0
bne loop

(mein ARM ist ein wenig rostig, aber Sie bekommen die Idee)

Nun wäre dies ein sehr einfacher Compiler und ein sehr einfacher Mikroprozessor, aber Sie können aus dem Beispiel ersehen, dass wir 8 Anweisungen pro Iteration der Schleife betrachten (7, wenn wir die '1' in ein anderes Register verschieben und die Last verschieben außerhalb der Schleife). Das ist nicht wirklich dicht. Die Codedichte wirkt sich auch auf die Leistung aus; Wenn Ihre Schleifen länger sind, weil der Code nicht dicht ist, benötigen Sie möglicherweise mehr Anweisungs-Cache, um die Schleife zu halten. Mehr Cache bedeutet einen teureren Prozessor, aber komplexe Befehlsdecodierung bedeutet wiederum mehr Transistoren, um den angeforderten Befehl zu entschlüsseln, also ist es ein klassisches technisches Problem.

ARM ist in dieser Hinsicht ziemlich nett. Jeder Befehl kann bedingt sein, die meisten Befehle können den Wert von Registern erhöhen oder verringern, und die meisten Befehle können optional die Prozessorflags aktualisieren. Auf ARM und mit einem mäßig nützlichen Compiler kann dieselbe Schleife etwa so aussehen:

movl r0, count_bytes
movl r1, s
movl r2, d
loop: ldrb r3, [r1++]
strb [r2++], r3
subs r0, r0, 1
bne loop

Wie Sie sehen können, besteht die Hauptschleife jetzt aus 4 Anweisungen. Der Code ist dichter, weil jede Anweisung in der Hauptschleife mehr macht. Dies bedeutet im Allgemeinen, dass Sie mit einer bestimmten Menge an Speicher mehr tun können, da weniger davon verwendet wird, um zu beschreiben, wie die Arbeit ausgeführt werden soll.

Nun hatte nativer ARM-Code oft die Beschwerde, dass er nicht superdicht sei; Dies hat zwei Hauptgründe: Erstens sind 32 Bit eine schrecklich "lange" Anweisung, sodass viele Bits für einfachere Anweisungen verschwendet zu werden scheinen, und zweitens wurde der Code aufgrund der Natur von ARM aufgebläht: Jede einzelne Anweisung ist 32 Bits lang, ohne Ausnahme. Dies bedeutet, dass es eine große Anzahl von 32-Bit-Literalwerten gibt, die Sie nicht einfach in ein Register laden können. Wenn ich "0x12345678" in r0 laden wollte, wie codiere ich eine Anweisung, die nicht nur 0x12345678 enthält, sondern auch "Literal nach r0 laden" beschreibt? Es bleiben keine Bits übrig, um die eigentliche Operation zu codieren. Der ARM-Lade-Literalbefehl ist ein interessantes kleines Biest, und der ARM-Assembler muss auch etwas schlauer sein als normale Assembler, weil er "fangen" muss

Wie auch immer, um diese Beschwerden zu beantworten, hat ARM den Thumb-Modus entwickelt. Statt 32 Bit pro Befehl beträgt die Befehlslänge jetzt 16 Bit für fast alle Befehle und 32 Bit für Verzweigungen. Es gab ein paar Opfer beim Thumb-Modus, aber im Großen und Ganzen waren diese Opfer einfach zu machen, weil Thumb Ihnen eine etwa 40%ige Verbesserung der Codedichte brachte, nur indem Sie die Befehlslänge reduzierten.

Ausgezeichnete Antwort. Wirklich ausgezeichnet.
Vergessen Sie nicht, Thumb2 zu erwähnen, was für die meisten Anwendungen eine noch größere Verbesserung darstellt.
Sehr interessant zu lesen. Ich lerne viel, indem ich einfach Fragen und Antworten auf dieser Seite lese.
Vielen Dank Andrew, ausgezeichnete Antwort, es hat mir bei meinen Zweifeln sehr geholfen :)
Dies könnte auch eine kurze Erwähnung der Auswirkungen von RISC auf die Codedichte gegenüber CISC erfordern (wobei RISC im Allgemeinen niedriger ist als CISC, da CISC-Architekturen tendenziell mehr Anweisungen haben, die mehr können, aber zu längeren/komplexeren Pipelines führen können, während RISC konzentriert sich auf einfachere Anweisungen, die einfachere Pipelines ermöglichen, daher ist die RISC-Codedichte geringer).

Die "Codedichte" eines Befehlssatzes ist ein Maß dafür, wie viel Material Sie in eine bestimmte Menge an Programmspeicher bekommen können oder wie viele Bytes Programmspeicher Sie benötigen, um eine bestimmte Menge an Funktionalität zu speichern.

Wie Andrew Kohlsmith betonte, können verschiedene Compiler selbst auf derselben MCU eine unterschiedliche Codedichte erzielen.

Vielleicht gefällt Ihnen die Lektüre von „Insekten der Computerwelt“ von Miro Samek, in dem verschiedene MCUs verglichen werden.