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

时间:2016-03-06 18:22:45

标签: assembly arm raspberry-pi bare-metal

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

打开LED(定位于烘焙程序,http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/)可以正常工作。

但现在我想做一些分支指令,而这似乎没有任何东西可以工作了:

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

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

C-v jjjj $

现在我想在代码的开头添加一个分支,跳过第一部分,以便只激活第二个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

但这都不起作用。

所以我的问题是:

  • 我如何执行这样的分支?
  • 我是否以正确的方式使用地址?

4 个答案:

答案 0 :(得分:1)

Bx或blx应该是您指示的第一选择。你可以进入电脑,但为什么要设置寄存器,推送和弹出,只需bx。并且可能有一些其他人可以正确修改电脑,不确定mov是否只有一个,但是文档会告诉你。

如果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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

虽然我不知道Raspbery Pi寄存器,但我认为此代码中存在一些问题:

  • 此程序似乎打开LED,而不是关闭。所以,即使你分支,它也不会眨眼。您需要一个寄存器,在该寄存器中反转该值,以便在循环期间LED处于开/关状态
  • 没有一些延迟,看到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

答案 3 :(得分:0)

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

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

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

disable_commandline_tags=1

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