为什么这段代码是由 avr-gcc 生成的?它是如何工作的?

发布于 2024-08-02 13:15:40 字数 699 浏览 12 评论 0原文

这是我正在开发的一个 C 项目中的反汇编 AVR 代码片段。我注意到生成了这个奇怪的代码,但我无法理解它是如何工作的。我假设这是某种荒谬的优化......

解释是什么?

92:         ticks++;         // unsigned char ticks;
+0000009F:   91900104    LDS       R25,0x0104     Load direct from data space
+000000A1:   5F9F        SUBI      R25,0xFF       Subtract immediate
+000000A2:   93900104    STS       0x0104,R25     Store direct to data space
95:         if (ticks == 0) {
+000000A4:   2399        TST       R25            Test for Zero or Minus
+000000A5:   F009        BREQ      PC+0x02        Branch if equal
+000000A6:   C067        RJMP      PC+0x0068      Relative jump

具体来说,为什么第二条指令从 R25 中减去 0xFF 而不是仅仅 INC R25

This is a snippet of disassembled AVR code from a C project I'm working on. I noticed this curious code being generated, and I can't understand how it works. I'm assuming it's some sort of ridiculous optimization...

What is the explanation?

92:         ticks++;         // unsigned char ticks;
+0000009F:   91900104    LDS       R25,0x0104     Load direct from data space
+000000A1:   5F9F        SUBI      R25,0xFF       Subtract immediate
+000000A2:   93900104    STS       0x0104,R25     Store direct to data space
95:         if (ticks == 0) {
+000000A4:   2399        TST       R25            Test for Zero or Minus
+000000A5:   F009        BREQ      PC+0x02        Branch if equal
+000000A6:   C067        RJMP      PC+0x0068      Relative jump

Specifically, why does the second instruction subtract 0xFF from R25 instead of just INC R25?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甚是思念 2024-08-09 13:15:40

SUBI 指令可用于将任何 8 位常数与 8 位值相加或相减。它与 INC 具有相同的成本,即指令大小和执行时间。所以SUBI是编译器首选的,因为它更通用。没有相应的 ADDI 指令,可能是因为它是多余的。

The SUBI instruction can be used to add/subtract any 8 bit constant to/from an 8 bit value. It has the same cost as INC, i.e. instruction size and execution time. So SUBI is preferred by the compiler because it is more general. There is no corresponding ADDI instruction, probably because it would be redundant.

夏见 2024-08-09 13:15:40

tl;dr 编译器被设计为使用更可移植、更高效的&一般解决方案在这里。

SUBI 指令集 C(进位)和 H(半进位)CPU 标志用于后续指令(顺便说一句,8 位 AVR 中没有 ADDI,因此添加立即数 x 我们从中减去 -x),而 INC 没有。由于 SUBIINC 有 2 个字节的长度并在 1 个时钟周期内执行,使用 SUBI 你不会丢失任何东西 - OTOH,如果你使用 8 位大小的计数器,你可以轻松检测它是否已翻转(通过 BRCC< /a>/BRCS),如果您有一个 16 位或 32 位大小的计数器,它允许您以非常简单的方式递增它 - 只需 INC0x00FF 就会得到增加到 0x0000,因此在 INC 之前必须检查最低字节是否为 0xFF。 OTOH,对于 SUBI,您只需 SUBI -1 最低字节,然后 ADC 0 为后续字节,确保所有潜在的进位位都有已被核算。

进一步阅读:

https://lists.gnu .org/archive/html/avr-gcc-list/2008-11/msg00029.html

http://avr-gcc-list.nongnu.narkive.com/SMMzdBkW/foo-subi-vs-inc

tl;dr the compiler was designed to use the more portable, efficient & general solution here.

The SUBI instruction sets C (carry) and H (half-carry) CPU flags for use with subsequent instructions (there is no ADDI in 8-bit AVR BTW, so to add an immediate value of x we subtract -x from it), whereas INC does not. Since both SUBI & INC have 2 bytes of length and execute during 1 clock cycle, you lose nothing by using SUBI - OTOH, if you use a 8-bit-sized counter, you can then easily detect if it has rolled over (by BRCC/BRCS), and if you'd have a 16- or 32-bit-sized counter, it allows you to increment it in a very simple way - with just INC, 0x00FF would get increased to 0x0000, so you'd have to check if the lowest byte is 0xFF before INCing. OTOH, with SUBI you just SUBI -1 the lowest byte, and then ADC 0 for the following bytes, assuring all the potential carry bits has been accounted for.

Further reading:

https://lists.gnu.org/archive/html/avr-gcc-list/2008-11/msg00029.html

http://avr-gcc-list.nongnu.narkive.com/SMMzdBkW/foo-subi-vs-inc

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文