Review A: Introducing ARM assembly language
printable versionA1: [1] // A2: [1] [2] [3] [4] [5] [6] [7] // A3: [1] [2] [3] [4] [5] [6] [7] [8] [9]
Problem A1.1
Define the fetch-execute cycle as it relates to a computer processing a program. Your definition should describe the primary purpose of each phase.
The fetch-execute cycle is the process by which a classical computer executes instructions. In the fetch phase, the computer determines which instruction to do next, by fetching that instruction from memory based on the current value of the program counter register. In the execute phase, the computer executes this instruction. The computer alternates between these two phases as long as it is on.
Problem A2.1
For the below ARM assembly code, trace the values
as it executes that will be placed into the registers
R4
, R5
, and R6
.
MOV R4, #7
MOV R5, #4
MOV R6, #4
again MOV R7, R4
ADD R4, R5, R4
MOV R5, R7
SUBS R6, R6, #1
BNE again
R4 |
7, | 11, | 18, | 29, | 47 |
R5 |
4, | 7, | 11, | 18, | 29 |
R6 |
4, | 3, | 2, | 1, | 0 |
Problem A2.2
Translate the below C code for counting the 1 bits in R0
into
ARM assembly code, using the registers indicated by the variable
names.
r3 = 1;
r1 = 0;
while (r3 != 0) {
if ((r0 & r3) != 0) {
r1 = r1 + 1;
}
r3 = r3 + r3;
}
MOV R3, #1
MOV R1, #0
loop TST R0, R3
ADDNE R1, R1, #1
ADDS R3, R3, R3
BNE loop
Problem A2.3
Suppose R0
contains an integer value a, and
R1
contains an integer value b that is more than
0. Write an ARM assembly language fragment that leaves in R2
the value of ab — that is,
R0
raised to the positive power found in R1
. You may
change the values in R0
and R1
, but the value for
R2
should be computed reflecting the initial R0
and R1
values.
MOV R2, #1
loop MUL R2, R2, R0
SUBS R1, R1, #1
BNE loop
Problem A2.4
Translate the below C fragment into an equivalent ARM assembly language
program, using registers corresponding to the variable names.
(As it happens, this code has the effect of placing into r2
the product of r0
and r1
's initial values.)
r2 = 0;
while (r1 != 0) {
if ((r1 & 1) != 0) {
r2 += r0;
}
r0 <<= 1;
r1 >>= 1;
}
while (1); // halting loop
MOV R2, #0
CMP R1, #0
BEQ halt
loop: TST R1, #1
ADDNE R2, R2, R0
MOV R0, R0, LSL #1
MOVS R1, R1, ASR #1
BNE loop
halt: B halt
Problem A2.5
For the below ARM assembly code, trace the values
as it executes that will be placed into the registers
R0
, R1
, and R2
.
MOV R0, #48
MOV R1, #5
MVN R2, #0 ; MVN, not MOV
loop1 ADD R2, R2, #1
CMP R0, R1, LSL R2
BGT loop1
SUBLTS R2, R2, #1
BLT done
loop2 CMP R0, R1, LSL R2
SUBGE R0, R0, R1, LSL R2
SUBS R2, R2, #1
BGE loop2
done
(By the way, this fragment computes R0
% R1
.)
R0 |
48, | 8, | 3 | ||||||||
R1 |
5 | ||||||||||
R2 |
−1, | 0, | 1, | 2, | 3, | 4, | 3, | 2, | 1, | 0, | −1 |
Problem A2.6
For the below ARM assembly code, trace the values
as it executes that will be placed into the registers
PC
, R0
, R1
, and R2
.
MOV R0, #0 ; at addr 0
MOV R1, #5
ADD R0, R0, R1
SUB R1, R1, #1
CMP R0, #10 ; at addr 16
MOVGT PC, #28
MOV PC, #8
MOV R2, #1
halt B halt ; at addr 32
[Technically, PC
would always be 4 more
than listed below. However, the below answer is more intuitive
and is acceptable, as long as you're consistent.]
PC : |
0, | 4, | 8, | 12, | 16, | 20, | 24, | 8, | 12, | 16, | 20, | 24, | 8, | 12, | 16, | 20, | 28, | 32 |
R0 : |
0, | 5, | 9, | 12 | ||||||||||||||
R1 : |
5, | 4, | 3, | 2 | ||||||||||||||
R2 : |
1 |
Problem A2.7
Explain what an ARM processor accomplishes in terms of accessing
and changing its registers when it executes a BEQ
instruction.
It looks at the Z flag to see whether the Z flag is 0 or 1.
If the Z flag is 0, then it changes R15
(the program
counter) to the address named within the instruction.
If the Z flag is 1, then it increases R15
by 4
(so that the next instruction
executed is the next instruction after the BEQ
instruction).
Problem A3.1
For the below ARM assembly code, trace the values
as it executes that will be placed into the registers
R0
, R1
, and R2
.
ADD R1, PC, #base ; puts 32 into R1
MOV R2, #0
loop LDR R0, [R1]
ADD R2, R2, R0
ADD R1, R1, R0
CMP R0, #0
BNE loop
halt B halt
base DCB 3, 4, 0, -2, 1, -3
R0 | 3 | −2 | 4 | −3 | 0 | |
R1 | 32 | 35 | 33 | 37 | 34 | 34 |
R2 | 0 | 3 | 1 | 5 | 2 | 2 |
Problem A3.2
For the below ARM assembly code, trace the values as it executes
that will be placed into the registers R1
, R2
, and
R3
. Note that
the first line places the number 32 into R0
.
ADD R0, PC, #nums ; places the address of nums[0] == 1 into R0
MOV R1, #0
loop ADD R2, R0, R1, LSL #2
LDR R3, [R2]
ADD R1, R1, R3
CMP R1, #10
BLT loop
done B done
nums DCD 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
R1 | 0 | 1 | 2 | 4 | 9 | 64 | ||||||||||
R2 | 32 | 36 | 40 | 48 | 68 | |||||||||||
R3 | 1 | 1 | 2 | 5 | 55 |
Problem A3.3
For the below ARM assembly code, trace the values
as it executes that will be placed into the registers
R0
, R1
, and R2
.
ADD R0, PC, #nums
loop LDRB R1, [R0], #1
SUBS R2, R1, #3
BLE loop
halt B halt
nums DCB 1, 2, 3, 4, 5
R0 |
20, | 21, | 22, | 23, | 24 |
R1 |
1, | 2, | 3, | 4 | |
R2 |
−2, | −1, | 0, | 1 |
Problem A3.4
For the below ARM assembly code, trace the values
as it executes that will be placed into the registers
R0
, R1
, and R2
.
ADD R0, PC, #nums
MVN R1, #8 ; makes R1 be -9
loop LDRB R2, [R0], #1
ADDS R1, R1, R2
BLT loop
halt B halt
nums DCB 1, 2, 3, 4, 5
R0 |
24, | 25, | 26, | 27, | 28 |
R1 |
−9, | −8, | −6, | −3, | 1 |
R2 |
1, | 2, | 3, | 4 |
Problem A3.5
Suppose R0
holds the address of the first entry in an
array of four-byte integers. Write an ARM assembly language
program fragment that places into R0
the index of the
first 0 in that array. (You may assume that there is a 0 in the
array.) For example, if the array is <9,7,8,0,6>,
and R0
holds the memory address of the 9,
your fragment will place 3 into R0
, since the 0 is in
slot 3 of the array.
SUB R2, R0, #4 ; R2 will be address of first zero found
again LDR R1, [R2, #4]!
CMP R1, #0
BNE again
SUB R0, R2, R0 ; now compute index corresponding to R2
MOV R0, R0, ASR #2 ; by subtracting R0 and dividing by 4
Problem A3.6
Suppose R0
holds the address of the first entry in an
array of four-byte integers, and R1
hold the number of
entries in that array. Write an ARM assembly fragment that places into
R0
the largest value of the array.
You may change any other registers,
and you may assume that the array contains at least one
value.
MOV R2, R0 ; R2 is address of next entry to read
LDR R0, [R2], #4 ; Initialize return value with first entry
B start
next LDR R3, [R2], #4 ; Retrieve next entry
CMP R3, R0 ; Update R0 if this entry is larger
MOVGT R0, R3
start SUBS R1, R1, #1 ; Test whether any entries are left
BNE next
Problem A3.7
Translate the below C code into ARM assembly code, using the
registers indicated by the variable names. The C code presumes that
r0
holds the address of the first entry of an array of integer
values, and r1
indicates how many elements the array holds;
the code removes all adjacent duplicates from the array.
r3 = 1;
for (r2 = 1; r2 < r1; r2++) {
if (r0[r2] != r0[r2 - 1]) {
r0[r3] = r0[r2];
r3 += 1;
}
}
r1 = r3;
MOV R3, #1
MOV R2, #1
loop CMP R2, R1
BLT done
LDR R4, [R0, R2, LSL #2]
SUB R5, R2, #1
LDR R5, [R0, R5, LSL, #2]
CMP R4, R5
STRNE R4, [R0, R3, LSL #2]
ADDNE R3, R3, #1
ADD R2, R2, #1
B loop
done MOV R1, R3
Problem A3.8
Suppose we have defined the following C struct
, which our C compiler has decided to compile with name
being in the first
four bytes and grade
in the next four bytes.
struct student {
char *name;
int grade;
};
Now suppose R0
holds the address of an array of twenty 32-bit pointers
to struct student
s; that is, each R0[i]
holds an address where
a struct student
can be found in memory.
Complete the below ARM assembly language fragment
as indicated; following completion of the full fragment,
R1
should become the sum of all grades in the course.
MOV R1, #0 ; R2 will hold total of all grades seen
MOV R2, #0 ; R2 is index where we are in array
again ; load R0[R2]->grade into R3
ADD R1, R1, R3 ; total += loaded grade
ADD R2, R2, #1 ; R2 += 1
CMP R2, #20 ; if R2 < 20, repeat
BLT again
LDR R3, [R0, R2, LSL #2]
LDR R3, [R3, #4]
Problem A3.9
Suppose we represent a linked list in memory where each node is eight bytes long, with the node's integer data stored in the first four bytes and the address of the following node found in the following four bytes. The list's last node is marked by having 0 as the address of its following node.
Assuming that R0
initially holds the
address of the list's first node,
write an ARM assembly language fragment that counts how many nodes
in a linked list have a negative number, placing the number
found into R1
.
MOV R1, #0 # no negative numbers found so far
loop TST R0, R0 # see if R0 is NULL
BEQ done
LDR R2, [R0] # load R0->data into R2
CMP R2, #0
ADDLT R1, R1, #1 # increment R1 if R2 < 0
LDR R0, [R0, #4] # load R0->next into R0, and repeat
B loop
done