关于代码密度及其定义


Answers:


24

代码密度宽松地指执行一个请求的动作需要多少微处理器指令,以及每条指令占用多少空间。一般来说,一条指令占用的空间越少,微处理器可以完成的每条指令的工作量就越大,其代码越密集。

我注意到您已经用'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代码通常会抱怨它不是很密集。这是由于两个主要原因:首先,32位是一个非常“长”的指令,因此,许多位似乎浪费在更简单的指令上;其次,由于ARM的性质,代码变得肿:每条指令都是32位长,无一例外。这意味着您不能将大量32位文字值加载到寄存器中。如果我想将“ 0x12345678”加载到r0中,我该如何编写一条不仅包含0x12345678的指令,还描述“将文字加载到r0”的指令?没有剩余的代码可以对实际操作进行编码。ARM加载文字指令是一个有趣的小野兽,并且ARM汇编程序也必须比普通汇编程序更聪明,因为它必须“捕捉”

无论如何,为了回答这些抱怨,ARM提出了Thumb模式。现在,几乎所有指令的指令长度为16位,分支的指令长度为32位,而不是每条指令32位。Thumb模式有一些牺牲,但是总的来说,这些牺牲很容易实现,因为Thumb仅仅通过减少指令长度就使代码密度提高了40%。


极好的答案。真的很棒。
2010年

不要忘了提到Thumb2,它对于大多数应用程序来说是一个更大的改进。
Yann Ramin

非常有趣的阅读。我在阅读本站点的问题和答案时学到了很多东西。
onaclov2000

非常感谢安德鲁,出色的回答,这对我的疑问
大有

这也可以简短地提及RISC与CISC对代码密度的影响(RISC通常低于CISC,因为CISC体系结构倾向于拥有更多可以执行更多指令的指令,但可能导致更长/更复杂的流水线,而RISC专注于允许更简单管线的更简单指令,因此RISC代码密度较低)。
JAB

1

指令集的“代码密度”是对可以在给定数量的程序存储器中放入多少东西,或者在存储给定数量的功能时需要多少字节程序存储器的度量。

正如Andrew Kohlsmith指出的那样,即使在同一MCU上,不同的编译器也会获得不同的代码密度。

您可能喜欢阅读 Miro Samek撰写的“计算机世界的昆虫”,该书比较了各种MCU。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.