裸机编程中的 ARMv6 分支(Raspberry Pi B+)

ARMv6 Branch in Bare Metal Programming (Raspberry Pi B+)

我正在尝试为 Raspberry Pi B+ 版本编写一个非常基本的交叉编译器来构建简单的裸机程序。我的编译器能够使用 ARM 指令集数据表将简单的命令翻译成相应的机器语言指令。

打开 LED(将自己定位到烘焙 pi 课程,http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/)工作正常。

但现在我想做一些分支指令,而这里似乎没有任何作用:

首先我想跳转到绝对地址,没有使用 B / BL 指令的相对分支。

为了测试分支,我使用了以下反汇编代码(使用 Hopper Disassembler V3 测试版反汇编),它打开了与 GPIO 16 和 22 连接的 LED:

00000000  mov r0, #0x20000000     ;Load the GPIO Base Address into R0
00000004  orr r0, r0, #0x200000
00000008  mov r1, #0x40           ;Load the Set Function Mask (for GPIO 22) into r1
0000000c  str r1, [r0, #0x8]      ;Store the Set Function Mask into the GPFSEL2
00000010  mov r1, #0x400000       ;Move the Set Output Mask (for GPIO 22) into r1
00000014  str r1, [r0, #0x1c]     ;Store the Set Output Mask into GPSET0

00000018  mov r0, #0x20000000     ;Load the GPIO Base Address into R0
0000001c  orr r0, r0, #0x200000
00000020  mov r1, #0x40000        ;Load the Set Function Mask (for GPIO 16) into r1
00000024  str r1, [r0, #0x4]      ;Store the Set Function Mask into the GPFSEL2
00000028  mov r1, #0x10000        ;Move the Set Output Mask (for GPIO 16) into r1
0000002c  str r1, [r0, #0x1c]     ;Store the Set Output Mask into GPSET0

00000030  b 0x30                  ;Infinity Loop to keep the processor up

现在我想在代码的开头添加一个分支,以跳过第一部分,以便仅激活第二个 LED。

我是这样试过的:

mov r15, #0x1c

但唯一的影响是两个 LED 都保持黑暗。

我的第二次尝试是这样的:

mov r2, #0x20
bx r2

但这都不起作用。

所以我的问题是:

您跳转到了错误的地址,您的程序加载到 0x8000。如果您使用标签,链接器应该为您计算地址。

虽然不了解树莓派的寄存器,但我觉得这段代码有几个问题:

  • 这个程序似乎是打开 LED,而不是关闭。所以即使你分支,它也不会眨眼。您需要一个寄存器,您可以在其中反转值,以便 LED 在循环期间为 On/Off
  • 没有一些延迟,看到 LED 闪烁的速度太快了。您可以添加延迟(库函数)、定时器中断或仅添加 for 循环(这将是一个分支)。

顺便说一下,延迟的 for 循环可能是这样的:

       MOV r0,  #1000  ; Start of the counter
loop:  SUBS r0, #1     ; Decrement the counter (Sets the flags for the branch)
       BNE  loop       ; Branch to loop label until r0 is 0

Bx 或 blx 应该是您的首选指令。您可以弹出到 pc,但为什么要设置一个注册、推送和弹出,只是 bx。并且可能还有其他一些可以正确修改 pc,不确定 mov 是否是一个但是 arm 文档会告诉你。

如果 bx 不适合您,那么您要么对 bx 进行了编码错误,要么没有将地址放入正确的寄存器中。

mov r3,#0x12000000
orr r3,r3,#0x00340000
orr r3,r3,#0x00005600
orr r3,r3,#0x00000078
bx r3

生产

   0:   e3a03412    mov r3, #301989888  ; 0x12000000
   4:   e383370d    orr r3, r3, #3407872    ; 0x340000
   8:   e3833c56    orr r3, r3, #22016  ; 0x5600
   c:   e3833078    orr r3, r3, #120    ; 0x78
  10:   e12fff13    bx  r3

并将分支到地址 0x12345678

感谢@TimothyBaldwin 的提示,我现在得到了答案(如果我自己写一个提供更多细节的答案而不是简单地接受他的答案,我希望它没问题)。

如@TimothyBaldwin 所述,问题是程序加载到 0x8000,如您在 https://raspberrypi.stackexchange.com/questions/10442/what-is-the-boot-sequence.

中的图表中所见

正如那里所解释的那样,在我的例子中,如果我在我的 config.txt 中添加以下行,它的效果非常好:

disable_commandline_tags=1

因为代码在 0x0 加载,一切都按预期工作。