2016-03-06 23 views
0

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

打开发光二极管(定位自己在烘烤pi当然,http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/)工作正常。

但现在我希望做一些分支指令,而这正是似乎没有任何工作了:

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

要测试一个分支,我使用下面的反汇编代码(使用料斗拆装V3测试版拆解),至极开启与GPIO 16 AND22连接的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 

但是,无论是作品。

所以我的问题是:

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

这可能是一个有趣的学习练习,gcc有一个'-white'选项来构建不依赖任何库的代码。我假设GNU汇编程序可以将ARM asm组装成一个扁平的二进制文件,所以你可以使用它来编写启动代码,以便运行你的编译器输出函数。据我了解,这基本上是如何构建Linux内核的:大多数是C语言,其中包含一些用于设置的asm,以及一个构建内核映像而不是ELF可执行文件的构建过程。 –

回答

0

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

正如@TimothyBaldwin所提到的那样,问题在于Programm在0x8000处加载,正如您在https://raspberrypi.stackexchange.com/questions/10442/what-is-the-boot-sequence的图表中看到的那样。

正如所解释的存在,在我的情况下,它完美的作品很好,如果我添加到我的config.txt以下行:

disable_commandline_tags=1 

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

0

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

+0

你从哪里得到这些信息?我目前没有使用汇编器/链接器,因为我想自己做这些东西来学习。 – Marben

+0

最好的学习场所是从工作的工具。使用gnu binutils进行组装,然后拆卸,并看看指令是如何构建的,如果是好的,不要总是为每种情况绘制精确的图片。 –

+0

或者如果你拒绝使用工作的汇编器,那么至少应该使用反汇编器来检查你创建的代码。 –

0

虽然我不知道Raspbery皮寄存器,我觉得有几个问题,在此代码:

  • 这个程序似乎点亮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 
+0

也许我在配方中有点不清楚,我的目标是不让LED闪烁,代码只是通过跳过一个LED的代码来测试分支是否实际工作,因此,那里只是一个LED发光。 – Marben

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

+0

,你可以根据需要混淆条件字段。 –