0
votes

I'm trying to write a very basic cross compiler for the Raspberry Pi B+ Version to build simple bare metal programmes. My compiler is able to translate simple commands into the corresponding machine language instruction, using the ARM Instruction Set Datasheet.

Turning on LEDs (orientating myself on the baking pi course, http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/) works fine.

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.

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:

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.

I tried it like that:

mov r15, #0x1c

but the only effect is that both LEDs stay dark.

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?
4
This might make an interesting learning exercise, gcc has a -ffreestanding option to build code that doesn't depend on any libraries. I assume the GNU assembler can assemble ARM asm into a flat binary file if you ask it to, so you can use that to write the startup code that sets up to run your compiler-output functions. As I understand it, this is basically how the Linux kernel is built: mostly C with some asm for setup, and a build process that makes a kernel image instead of an ELF executable.Peter Cordes

4 Answers

1
votes

Bx or blx should be your first choices for instructions. You can pop into the pc, but why setup a register, push, and the pop, just 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.

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.

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

0
votes

You are branching to the wrong address, your program is loaded at 0x8000. If you use labels the linker should calculate the addresses for you.

0
votes

Although I don't know the Raspbery Pi registers, I think there are several problems in this code:

  • This program seems to turn on the LED, not off. 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
  • Without some delay, it will be far too fast to see the LED blink. You can either add a delay (library function), an interrupt from a timer, or just a for loop (Which will be a branch).

By the way, the for loop for the delay may be something like:

       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
votes

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).

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.

As explained there, in my case it works perfectly nice if I add to my config.txt the following line:

disable_commandline_tags=1

because then the code is loaded at 0x0, and everything works as expected.