回答:
コード密度とは、要求されたアクションを実行するために必要なマイクロプロセッサ命令の数と、各命令が占めるスペースの量を大まかに指します。一般的に言えば、命令が占めるスペースが少なく、マイクロプロセッサが実行できる命令ごとの作業が多いほど、コードの密度が高くなります。
質問に「arm」タグを付けたようです。ARM命令を使用してコード密度を説明できます。
メモリのある場所から別の場所にデータのブロックをコピーするとします。概念的には、高レベルのコードは次のようになります。
void memcpy(void *dest, void *source, int count_bytes)
{
char *s, *d;
s = source; d = dest;
while(count_bytes--) { *d++ = *s++; }
}
これで、単純なマイクロプロセッサ用の単純なコンパイラがこれを次のようなものに変換できます。
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
(私のARMは少し錆びていますが、アイデアはわかります)
これは非常に単純なコンパイラと非常に単純なマイクロプロセッサになりますが、ループの反復ごとに8つの命令を確認していることがわかります(「1」を別のレジスタに移動してロードを移動すると7ループの外)。それは実際にはまったく密度が高くありません。コード密度もパフォーマンスに影響します。コードが密でないためにループが長い場合は、ループを保持するためにより多くの命令キャッシュが必要になる場合があります。より多くのキャッシュはより高価なプロセッサを意味しますが、再び複雑な命令のデコードは、要求された命令を解読するためにより多くのトランジスタを意味するため、これは古典的なエンジニアリングの問題です。
この点でARMは非常に優れています。すべての命令は条件付きであり、ほとんどの命令はレジスタの値をインクリメントまたはデクリメントでき、ほとんどの命令はオプションでプロセッサフラグを更新できます。ARMおよび中程度に有用なコンパイラでは、同じループは次のようになります。
movl r0, count_bytes
movl r1, s
movl r2, d
loop: ldrb r3, [r1++]
strb [r2++], r3
subs r0, r0, 1
bne loop
ご覧のとおり、メインループは4つの命令になっています。メインループ内の各命令がより多くのことを行うため、コードはより密集しています。これは一般的に、作業の実行方法を説明するために使用されるメモリが少ないため、特定のメモリ量でより多くのことを実行できることを意味します。
現在、ネイティブARMコードには、それが超高密度ではないという不満がしばしばありました。これは2つの主な理由によるものです。1つ目は、32ビットは非常に「長い」命令なので、単純な命令では多くのビットが無駄になるようです。2つ目は、ARMの性質によりコードが肥大化しました。例外なくビット長。これは、レジスターにロードできない32ビットのリテラル値が多数あることを意味します。「0x12345678」をr0にロードしたい場合、0x12345678が含まれているだけでなく、「リテラルをr0にロード」を記述する命令をどのようにコーディングすればよいですか?実際の操作をコーディングするためのビットは残っていません。ARMロードリテラル命令は興味深い小さな獣であり、ARMアセンブラは「キャッチ」する必要があるため、通常のアセンブラよりも少し賢くなければなりません。
とにかく、これらの不満に答えるために、ARMはThumbモードを考え出しました。命令あたり32ビットではなく、命令の長さがほとんどすべての命令で16ビットになり、分岐で32ビットになりました。Thumbモードではいくつかの犠牲がありましたが、概してこれらの犠牲は、命令の長さを減らすだけでThumbがコード密度を40%向上させるようなものになったため、簡単に作成できました。
命令セットの「コード密度」は、特定の量のプログラムメモリに格納できるものの量、または特定の量の機能を格納するために必要なプログラムメモリのバイト数の尺度です。
Andrew Kohlsmithが指摘したように、同じMCUであっても、コンパイラーが異なれば、コード密度も異なります。
さまざまなMCUを比較するMiro Samekによる「コンピュータの世界の昆虫」をお読みください 。