什么是装配中的偏移量以及如何使用它们?

时间:2014-03-26 19:57:31

标签: assembly arm

在下面的代码中,该人将寄存器指向一个地址,我明白了。为什么以后他没有将R3加载到R1中,为什么它必须偏移0x14?

R1是如何在几行代码中移动的?是什么让它做到了?这让我很困惑,而且几个小时的搜索也没有明确的答案。

代码从这里被盗。

http://mbed.org/forum/mbed/topic/3205/

my_asm

    ; setup a pointer to the base address of port 1
    LDR     R1,=0x2009c020      ; pointer to base of port1 

    LDR     R3,=0x00040000      ; set LED 1 port pin to output
    STR     R3,[R1,#0x00]       ; set direction bits (base+0x00)


loop
    LDR     R3,=0x00000000      ; set LED 1 off (all bits 'zero')
    STR     R3,[R1,#0x14]       ; set outputs directly (base+0x14)

    LDR     R3,=0x00040000      ; set LED 1 on (bit 18 aka P1.18 is 'one')
    STR     R3,[R1,#0x14]       ; set outputs directly (base+0x14)

    B       loop                ; branch to loop (endless loop!)

    ALIGN
    END

3 个答案:

答案 0 :(得分:4)

在汇编程序中使用偏移量来访问数据结构。

在您使用的代码中,您可以看到正在加载的基本地址。这是数据结构的起始地址。

数据结构将在某个地方定义,但不在代码中定义。该定义通常作为表格显示,例如

  • 的4个字节
  • 2个字节
  • 4字节用于别的东西

现代处理器使用这样的存储器映射进行输入和输出。每个设备都“映射”到特定地址。这是代码中的基地址。

在不知道处理器附带了什么硬件的情况下,我们无法告诉您数据结构中包含的内容。

答案 1 :(得分:0)

原因是它是实现所需效果的最短(最少指令)方式。正在做两件事:(1)配置端口以进行输出,以及(2)切换输出。由于为了执行这些操作而需要写入的存储器位置在附近,因此使用处理器的基本/偏移设施来解决这两个问题。

使用以下代码可以实现相同的效果,但没有任何好处。它更大(不太可能适合固定存储)并且循环不会更快(执行STR指令时处理器仍然必须在R1中将新值加零)。

my_asm
    ; setup a pointer to the base address of port 1
    LDR     R1,=0x2009c020      ; pointer to base of port1 

    LDR     R3,=0x00040000      ; set LED 1 port pin to output
    STR     R3,[R1,#0x00]       ; set direction bits (base+0x00)

    LDR     R1,=0x2009c034      ; pointer to port1 outputs         <-- change R1

loop
    LDR     R3,=0x00000000      ; set LED 1 off (all bits 'zero')
    STR     R3,[R1,#0x00]       ; set outputs                      <-- no more offset

    LDR     R3,=0x00040000      ; set LED 1 on (bit 18 aka P1.18 is 'one')
    STR     R3,[R1,#0x00]       ; set outputs                      <-- no more offset

    B       loop                ; branch to loop (endless loop!)

    ALIGN
    END

答案 2 :(得分:0)

寄存器1 正在加载端口1 的基地址和第三条指令......

STR     R3, [R1, #0x00]       ; set direction bits (base + 0x00)

...建议R1内容寻址的数据的第二个字节是端口1上LED的方向位。

理论上,您可能会在此指令完成后加载R1以在偏移量0x014处寻址数据,但这意味着您需要包含额外的 - 不必要的 - 指令。通常情况下,如果您正在使用Assembly编写某些内容,那么您尝试尽可能高效地执行此操作。

STR     R3, [R1, #0x14]       ; set outputs directly (base + 0x14)

您可以从上面的代码中学到的是方向指示器位于偏移1处且输出位于与端口1相关的数据中的字节15(我认为)。除此之外,我们没有任何信息。

但是,如果您需要在此过程中稍后访问与端口1相关的任何其他数据,并且已将基址寄存器更新为指向端口1记录开头之后的偏移量0x14,则必须加载地址,或重新加载基数并获得偏移量,特别是如果它位于端口1和偏移量14的数据基础之间。

如果您使用特定记录/数据片段,使用基址寄存器并对其进行偏移,而不是在每次需要时希望更新的存储器中加载具有直接地址的寄存器,则效率更高这样做。