简体   繁体   English

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

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

I'm trying to write a very basic cross compiler for the Raspberry Pi B+ Version to build simple bare metal programmes. 我正在尝试为Raspberry Pi B +版本编写一个非常基本的交叉编译器,以构建简单的裸机程序。 My compiler is able to translate simple commands into the corresponding machine language instruction, using the ARM Instruction Set Datasheet. 使用ARM指令集数据表,我的编译器能够将简单命令转换为相应的机器语言指令。

Turning on LEDs (orientating myself on the baking pi course, http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ ) works fine. 打开LED(使自己适应烘焙pi课程, http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ )可以正常工作。

But now i want to do some branch instructions, and this is where nothing seems to work anymore: 但是现在我想做一些分支指令,这似乎不再起作用了:

First i would like to branch to absolute addresse, no relative branches using the B / BL instruction. 首先,我想跳转到绝对地址,不使用B / BL指令进行相对跳转。

To test a branch, I'm using the following disassembled code (disassembled using the Hopper Disassembler V3 Test Version), wich turns on a LED connected with GPIO 16 and22: 为了测试分支,我使用以下反汇编代码(使用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

Now I want to add a branch to the beginning of the code, to skip the first section, so that only the second LED is activated. 现在,我想在代码的开头添加一个分支,以跳过第一部分,以便仅激活第二个LED。

I tried it like that: 我这样尝试过:

mov r15, #0x1c

but the only effect is that both LEDs stay dark. 但唯一的效果是两个LED均保持熄灭。

My second attempt is like that: 我的第二次尝试是这样的:

mov r2, #0x20
bx r2

But that neither works. 但这都不起作用。

So my question is: 所以我的问题是:

  • How do I perform such a branch? 如何执行这样的分支?
  • Am I using the Addresses the right way? 我使用地址的方式正确吗?

Bx or blx should be your first choices for instructions. Bx或blx应该是您的首选指示。 You can pop into the pc, but why setup a register, push, and the pop, just bx. 您可以弹出PC,但是为什么要设置寄存器,推送和弹出,只是bx。 And there may be some others that can correctly modify the pc, not sure if mov is one but the arm docs will tell you. 可能还有其他一些可以正确修改PC的东西,不确定mov是否是一个,但是arm文档会告诉您。

If bx is not working for you then you are either encoding the bx wrong or you are not placing the address in the register right. 如果bx对您不起作用,则说明您对bx的编码错误,或者没有将地址正确放在寄存器中。

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

produces 产生

   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

and will branch to address 0x12345678 并将分支到地址0x12345678

You are branching to the wrong address, your program is loaded at 0x8000. 您分支到错误的地址,您的程序已加载到0x8000。 If you use labels the linker should calculate the addresses for you. 如果使用标签,则链接器应为您计算地址。

Although I don't know the Raspbery Pi registers, I think there are several problems in this code: 尽管我不知道Raspbery Pi寄存器,但我认为这段代码中存在一些问题:

  • This program seems to turn on the LED, not off. 该程序似乎打开了LED,而不是关闭。 So even if you branch, it will not blink. 因此,即使分支,它也不会闪烁。 You need a register in which you invert the value so that the LED is On/Off during the loops 您需要一个寄存器,在其中将值取反,以便在循环期间LED亮/灭
  • Without some delay, it will be far too fast to see the LED blink. 没有任何延迟,看到LED闪烁将太快。 You can either add a delay (library function), an interrupt from a timer, or just a for loop (Which will be a branch). 您可以添加一个延迟(库函数),一个计时器中断或一个for循环(将是一个分支)。

By the way, the for loop for the delay may be something like: 顺便说一句,延迟的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

Thanks to the hint from @TimothyBaldwin I've got now the answer (I hope its okay if I write a own answers providing more details instead of simply accepting his one). 感谢@TimothyBaldwin的提示,我现在有了答案(我希望如果我自己写一个答案提供更多细节而不是简单地接受他的答案,那也可以)。

As mentioned by @TimothyBaldwin, the Problem was that the Programm is loaded at 0x8000, as you can see in the diagram found at https://raspberrypi.stackexchange.com/questions/10442/what-is-the-boot-sequence . 正如@TimothyBaldwin所提到的那样,问题在于该程序已加载到0x8000,如您在https://raspberrypi.stackexchange.com/questions/10442/what-is-the-boot-sequence上的图中所看到的。

As explained there, in my case it works perfectly nice if I add to my config.txt the following line: 如此处所述,如果我将以下行添加到config.txt中,则可以很好地工作:

disable_commandline_tags=1

because then the code is loaded at 0x0, and everything works as expected. 因为随后代码会在0x0加载,并且一切正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM