裸机编程中的 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 加载,一切都按预期工作。
我正在尝试为 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 加载,一切都按预期工作。