Skip to content
Newer
Older
100644 88 lines (57 sloc) 4.96 KB
3b8bf3d @singpolyma branching and conditionals
authored Sep 8, 2012
1 = Branches and Conditionals =
2
d508dae @singpolyma TODO about RAM layout
authored Sep 11, 2012
3 # TODO: more about how a program is laid out in RAM
4
3b8bf3d @singpolyma branching and conditionals
authored Sep 8, 2012
5 So far the instructions we have seen only allow us to give the computer a fixed-size list of things to do. Once all of the instructions have run, the program is done. What if we wanted to do something simple like subtract 6 from r0 the number of times that are stored in r1?
6
7 Well, first we will need a way to run instructions more than once. To do this, we use the `b` instruction:
8
9 doing:
10 sub r0, r0, #6
11 b doing
12
13 What is this `doing:`? Any word at the start of a line followed by a colon is a "label". A "label" marks a position in the code so that we can refer to it elsewhere. This is because instructions may get loaded into the computer's RAM anywhere, and so we might not know ahead of time where and given instruction is in order to jump to it. Labels solve this problem, and also let us use nice names that make sense to us instead of obscure numbers representing locations in RAM.
14
15 If you run this program, it will never finish. That's because the `b` instruction just causes the CPU to jump (or "branch") to the `doing` label. So it will just keep running that subtract instruction forever.
16
17 To solve this problem, ARMv6 allows us to put a specifier on the end of any instruction to say that some condition must be true in order for the instruction to run. For example, to branch only if something is equal to something else, we can use `beq` instead of just `b`, or `bne` to branch if they are not equal.
18
2af79a2 @singpolyma More verbosity about how `cmp` works
authored Sep 11, 2012
19 We also need a way to say what things we are testing for equality. The simplest instruction for doing this is `cmp`, which takes two arguments and, instead of storing a result somewhere that you can access, changes the value that the CPU uses for conditional execution of any instructions. For example in:
3b8bf3d @singpolyma branching and conditionals
authored Sep 8, 2012
20
21 doing:
22 sub r0, r0, #6
23 sub r1, r1, #1
24 cmp r1, #0
25 bne doing
26
2af79a2 @singpolyma More verbosity about how `cmp` works
authored Sep 11, 2012
27 The `cmp` causes the `bne` to only execute if r1 and 0 are not equal.
28
29 The above code will keep subtracting 6 from r0, and 1 from r1, until r1 equals 0. What if r1 starts at 0? Then the first subtraction (which runs before we check for equality) will cause it to no longer equal 0, and it only goes down from there, so the program will run forever. Lets fix that:
3b8bf3d @singpolyma branching and conditionals
authored Sep 8, 2012
30
31 b loopcond
32 doing:
33 sub r0, r0, #6
34 sub r1, r1, #1
35 loopcond:
36 cmp r1, #0
37 bne doing
38
39 Now we check the condition before starting the loop. We could also write it like this:
40
41 doing:
42 cmp r1, #0
43 subne r0, r0, #6
44 subne r1, r1, #1
45 bne doing
46
47 This way, the subtractions and branch will never happen if r1 is equal to 0, and we have less branches happening (since we don't need to jump to the end to do the comparison). This can matter because branch instructions cause CPUs to lose some of the smart things they do in order to go faster (because they suddenly are executing code from somewhere else than they might have expected).
48
31e8d07 @singpolyma TODO about pipelining
authored Sep 11, 2012
49 # TODO: Talk about pipelining here? Later? Earlier?
50
3b8bf3d @singpolyma branching and conditionals
authored Sep 8, 2012
51 So now we have a program that can do something to r0 based on r1. What if we wanted to do this many times in our program? Would we have to copy this code everywhere?
52
53 Well, we can run this code from anywhere in our program (with `b doing`), but how would it get back to us? Right now it would just keep running whatever instructions came next.
54
55 Maybe we could store the location to come back to in a register? But how do we know where we are? Well, we could use labels, like so:
56
57 mov r14, comeback
58 b doing
59 comeback: ...rest...
60
61 This would work, but then we have to come up with a unique label name for every place we want to do this. Luckily, the CPU also needs to know where we are in order to load and run the next instruction. It stores the location in register 15, which we can also call "pc" (for "Program Counter"):
62
63 mov r14, pc
64 b doing
65
66 But of course, we don't want to come back to exactly our current instruction, since then we will just branch to `doing` again right away!
67
68 mov r14, pc
69 add r14, r14, #8
70 b doing
71
b8ee490 @singpolyma Be more explicit that this is how ARM does it
authored Sep 11, 2012
72 It turns out that wanting to do this is common enough, that ARM has a special instruction name for it: `bl` (or "Branch and Link"). It always stores the place we want to come back to in register 14, sometimes called `lr` (for "Link Register").
3b8bf3d @singpolyma branching and conditionals
authored Sep 8, 2012
73
74 bl doing
75
76 Of course, we would also need to modify `doing` to come back.
77
78 doing:
79 sub r0, r0, #6
80 sub r1, r1, #1
81 cmp r1, #0
82 bne doing
83 b lr
84
85 Now we can set r0 and r1 from anywhere in our code, and then cause `doing` to operate on them. But what if we didn't want doing to modify r1? What if we still need that value? Well, we could just `mov r3, r1` or something, but what if we were using r3 for something? `doing` can't know what registers the code that calls it is using, and even we as the programmer can't know for sure how we will use it in the future. We could be careful to use only certain registers, but what if we needed those in a new place later on? What if we had some code that needed almost *all* of the registers?
86
87 The solution to this, as we will see, is to store things in RAM and not just in registers.
Something went wrong with that request. Please try again.