Solutions for the Assembler Homework
Question 1
In order to load the value 0x1a0 into register x6, we can use the addi
instruction with the zero register and the required constant value as operands:
addi x6, x0, 0x1a0
Note however that this only works if the MSB of the 12 bit constant is 0, since the immediate value is sign extended. So if for example, we try the following:
addi x6, x0, 0xeff
then the constant value 0xeff (which is -257 when interpreted as a 12 bit signed integer) will be sign
extended and we end up with the value 0xfffffeff in register x6 (which is
also -257 when interpreted as a 32 bit signed integer). What we really wanted
was 0x00000eff, which corresponds to 3839 in decimal, or -257 + 4096. So
actually we obtained a value that is wrong by -4096, which happens to be the
weight of the MSB in signed 12 bit integer representation.
To correct this offset, we would need to add 4096 to the result. Unfortunately,
we cannot use addi for this, because 4096 cannot be represented as a 12 bit
signed constant. Enter lui (load upper immediate): If we load a 20 bit constant to the upper part of a register using this
instruction, the lowest bit coincides with bit 12. So loading the constant 1 to
this bit creates the value 4096, which we needed to compensate for the sign
extension:
lui x6, 1 # Set x6 to 4096
addi x6, x6, 0xeff # Add -257 to x6
If you run this snippet in Ripes, you will see that it does the trick.
Question 2
With the above explanations, the second question is quickly answered:
- Use
luito set the upper 20 bits of the register - Use
addito set the lower 12 bits of the register
Again, this works fine if the 11th bit is zero, so we don't have to compensate for the sign extension:
lui x6, 0xbeef0
addi x6, x6, 0x1a0
leads to the expected result of 0xbeef01a0 in x6. If however the 11th bit of
the constant is high, then we just need to add 1 to the 20 bit constant. So in
order to set x6 to 0xdeadbeef, the following snippet works:
lui x6, 0xdeadc # This is 0xdeadb + 1
addi x6, x6, eef
Question 3
The variable i is stored at the beginning of the .data section at address
0x10000000. In order to access it, we need to have this address in a register.
For this, we can use the lui+addi schema from the previous question. It's
even easier since the lower bits are all zero, so we only need lui:
lui x4, 0x10000 # Set x4 to 0x10000000, the address of i
Note that there is a pseudo-instruction la (load address) that achieves the
same thing with the additional convenience that we can use the label of the
required address:
la x4, i
Now that we have the address of i in register x4, we can do the following in order to increment i:
- Load the value of
iinto a register - Increment the register
- Store the new value at the address of
i
This is straight forward in assembler:
lw x5, 0(x4) # Load i into x5
addi x5, x5, 1 # Add 1 to x5
sw x5, 0(x4) # Store i
Here is he complete snippet:
lui x4, 0x10000 # You can also use la x4, i
lw x5, 0(x4)
addi x5, x5, 1
sw x5, 0(x4)
.data
i: .word 127 # Initial value of i
Question 4
Here is a possible solution:
lui x4, 0x10000 # Load i to x5
lw x5, 0(x4)
bne x5, x0, final # If i != 0, jump to the final part
li x5, 1 # This is the "if" part
final:
addi x5, x5, 1 # Increment i
sw x5, 0(x4) # Store i
.data
i: .word 0
You can test the different conditions by changing the value of i before
executing the code in Ripes.
Note that we have inverted the original condition (i == 0 in C) by using the
bne (branch if not equal) instruction. In this way we avoid an additional
jump, since the fall through code after the branch is only executed if the
condition is false.
Question 5
Here is a possible solution:
lui x4, 0x10000 # Load i to x5
lw x5, 0(x4)
bne x5, x0, else # If i != 0, jump to the else part
li x5, 1 # This is the "if" part
jal x0, final # Need to skip the else part, could also use j final
else:
sub x5, x0, x5 # This is the else part
final:
addi x5, x5, 1 # The two branches join here again
sw x5, 0(x4) # Store i
.data
i: .word -6
The only thing that changes is the additional label else and the fact that we
need to (unconditionally) skip to the final part after the if part using the
jal instruction.
Question 6
Here is a possible solution:
lui x4, 0x10000 # Load i to x5
lw x5, 0(x4)
li x6, 10 # Upper limit of loop counter
li x7, 0 # Loop counter in x7
loop:
bge x7, x6, final # If loop counter reaches 10, jump to the end
addi x5, x5, 10 # i = i + 10
addi x7, x7, 1 # Increment loop counter
jal x0, loop # Do it again!
final:
sw x5, 0(x4) # Don't forget to store i
.data
i: .word 0 # Initial value of i
The structure of the above code is closer to the "while" version of the C code.
Note that we have inverted the condition in the while statement by using the
bge (branch if greater or equal) instruction, so we exit the loop once the
condition evaluates to false.