MIPS - loading individual bits - mips

Fellow SO users,
If I have a value, say 1010 saved in memory, how do I load each of the bits starting from the MSB to the LSB one at a time? By this I mean,
while loop
load $t1 with 1
shift some number by the amount indicated by the value in $t1 (1)
load $t1 with 0
shift some number by the amount indicated by the value in $t1 (0)
do the same until you load the LSB which is 0
start again at MSB (rotate right?)
end loop
I need some tips on how to declare this value in memory in the .data segment first. Do I declare this as:
value: .byte 00001010
And how do I load the individual bits into registers?
Kind regards

You can do this with the SLT instruction described here. Here is some pseudocode:
lbu $s0, value # load the byte
sll $s0, $s0, 24 # shift it into the upper byte of $s0
for (i = 0; i < 8; i++) {
# $t0 is set to 1 if the sign bit (i.e. bit 31) of $s0 is set
slt $t0, $s0, $zero
# $t0 now holds the value of the ith bit of value
. . . . # do something with $t0
sll $s0, $s0, 1 # shift on to the next bit
}
Implementing the for loop in assembler is left as an exercise for the reader.

Related

Write into next byte of a register

I understand that registers in memory are 32 bits. I also understand that lb will load contents from memory into the lower 8 bits of a register, and that if I did
lb $t1, $a3
lb $t1, 4($a3)
The second lb command will overwrite the contents loaded in the first. However, is there a way to write into the second byte of a register (loading from a different part in memory, so not two bytes right next to each other) and preserve the information of the first byte?
I am assuming what you want to use here is lbu (load byte unsigned) and not lb because you don't want the register to be sign extended (e.g. copying the byte AA in the register will result in 000000AA, and not FFFFFFAA).
If you want to write to the second byte of a register you can first use lbu to load the byte from memory to another register, then shift left 8 bits, and addu it to the original register.
For example:
lbu $t1, $a3 # 0x000000AA
lbu $t2, 4($a3) # 0x000000BB
sll $t2, $t2, 8 # 0x000000BB -> 0x0000BB00
addu $t1, $t1, $t2 # 0x000000AA + 0x0000BB00 = 0x0000BBAA

Replacing left logical shifts with other instructions in MIPS

So let's say that we have two registers $s0 and $s1. Register $s0 can take values from 0 to 31 and is used to show how many bits register $s1 will be shifted left. How can i do this without using sll or srl. I know that left logical shift by n bits is the same as multiplying with 2^n. This exercise gives a hint that this can be done with 4 instructions only. Both registers are 32-bit.
You can add $s1 to itself $s0 times (each time it will multiply its value by 2 which shifts its bits left once).
The code would look like this:
beqz $s0, end
loop:
add $s1, $s1, $s1
subu $s0, $s0, 1
bnez $s0, loop
end:
The first conditional branch is to ensure no action is taken to $s1 when $s0 holds value zero.

confusion in MIPS storing bits,

hi im trying to store a bit into a temp. register. Am i doing this correctly? and while i am at it, i am trying to see how many 1's are in the binary forms of a decimal number (0-16) am i doing this right? here is the chunk of code that matters, the rest works fine(just output and what not)
# for (i = 0; i <= 16; i++)
li $s0, 0 # i = 0
li $s3, 0 #constant zero
li $s4, 0 #i-2=0
bgt $s0, 16, bottom
top:
# calculate n from i
# Your part starts here
sb $t1, ($s0) #store LSB from number i in t1
sltu $t7,$s3,$t1 # check if t1 is a 1, if it is set t7 = 1
add $s1 ,$s3,$t1 # add 1 to n
ble $s4, 7, bloop # loop through rest of bits
bloop:
srl $t7, $s0, 1 # move bits in i right one, bringing in a zero from the left
sltu $t6, $s3, $t7 # check if t7 is a 1, if it is set t6 to 1
add $s1, $t6, $s1 # add increment n up 1
bgt $s4, 7, continue # break out of loop
continue:
Lets look at your code:
li $s0, 0
li $s3, 0
li $s4, 0
these instructions set the 3 registers $s0, $s3, and $s4 to 0
bgt $s0, 16, bottom
Branch to bottom if $s0 is greater than 16. Now $s0 will be 0 initially, and you have not labels before this, so there's no way to get back here, so this branch will never be taken. Also, it won't even assemble, as you never define the bottom label anywhere.
top:
The label top, so you can branch back to here as a loop -- but your code has no branches to top, so it never actually will.
sb $t1, ($s0)
store a byte from $t1 at the address given by $s0. Now the first time into the loop, $t0 has never been set to anything, so what are you storing? Worse, $s0 has been set to 0, so you're storing at address 0, which will crash (give a runtime error).
So this store really makes no sense. It's storing garbage to an invalid address.
sltu $t7,$s3,$t1
This compares $s3 to $t1 and sets $t7 to 0 or 1 depending on whether $s3 is less than $t1. $t1 is still garbage (you've never put anything into it), but it turns out that doesn't matter as $s3 is 0, so the comparison will always be false. Not that it matters anyways, as you never use $t7 for anything after this.
add $s1 ,$s3,$t1
Add $s3 (which is 0) to $t1 (which is garbage), and store the result(garbage) in $s1
ble $s4, 7, bloop
bloop:
Compare $s4 to 7 and branch if it is less than 7. Since $s4 is 0, it will branch, but since bloop is immediately after this, the branch has no effect. So this (and the label) might was well be deleted, as they don't do anything.
srl $t7, $s0, 1
shift $s0 left 1 bit position and store it into $t7. $s0 was set to 0 above, and shifting 0 gives 0, so this stores 0 in $t7.
sltu $t6, $s3, $t7
compare $s3(0) to $t7(0) and store the less-than result in $t6 (0)
add $s1, $t6, $s1
add $t6 to $s1, putting the result in $s1 -- this is the first instruction since the first three li instructions that makes any kind of sense. But as $t6 was zer0, it doesn't actually do anything
bgt $s4, 7, continue
continue:
Another branch that does nothing as the target is right after the branch.
So overally, you code looks like a bunch of randomly chosen instructions that don't do anything sensible. There's no loop, despite comments about looping. There nothing related to "bits" at all, despite title of the question.

writing iteration in MIPS

I am writing this program in MIPS to calculate 2 to a power given by me and sum the sequential powers down to 0. For example, if I put 4 in $a0 like in the code below, I want it to calculate (4^2)+(3^2)+(2^2)+(1^2) which should come out to be 15. It should stop before it reaches zero. This is what I have written so far
main:
addi $a0, $zero, 4 #put k in $a0 in this case
addi $a1, $zero, 0 #put 0 in current sum
addi $v1, $v1, 0 #tally the total in $v1
for:
lw $10, $a0 #load k into reg $10
lw $11, $a1 #load sum into $11
addi $10, $10, -1 #subtracts 1 from k
li $9, 0 #sets i in for loop ($9) to 0
done:
li $v0, 10
syscall
I'm new to MIPS and could use a lot of help on finishing this, I know I want to use a for loop, but I don't know how to go through it while subtracting 1 from k and also calculating the sum. How would I bring 2 to a power of k, because I guess there is no power operation in mips. At this point in the course I can only use add, sub, and, or, slt, addi, j, beq, lw, sw, and sll. Can you not use a constant when using sub? Thank you for any help
A power is a multiplication, and a multiplication is a sum. So you can write a function that does a multiplication by adding, and another function that does power by multiplicating. For example, the multiplication function:
multiply: # $a0 first factor, $a1 second factor, $v0 result of multiplication
or $t0, $zr, $zr
or $t1, $a1, $a1
or $t3, $zr, $zr
loop:
beq $t1, $zr, end
add $t0, $t0, $a0
addi $t1, $t1, -1
j loop
nop
end:
or $v0, $t0, $0
jr $ra
nop
(Please note I haven't tested this, and this will not work with negative numbers)
As a side note, you have MUL instruction as well, but I don't know if you saw that already.
I think the concept your instructor is trying to show you is that sll, in effect, multiplies by 2. You've got to think in binary. For example, let's start with 1:
0000 0000 0000 0000 0000 0000 0000 0001
Do a 'sll' on that, and what do you end up with? 0010 = 2. sll again and you get 0100 = 4. And so on, until you shift all the way over and have 0x80000000.
So the answer to the question, "How would I bring 2 to a power of k?", is simpler than you might have thought: you shift 1 by k.
# $t0 contains 'k', the amount we want to shift by
addi $t1, $zero, 1
sllv $t3, $t1, $t0
Note: I had to double-check that you can shift by a variable amount, but this link says sllv is valid. However, since it's not in your list of allowed functions, you'll have to do sll $t1, $t1, 1 in a loop. (Be sure to put your check at the start of the loop, in case the amount you want to shift by is zero!)
Quick question:
Are you doing 2^4+2^3.. etc? or 4^2+3^2 etc?
Just a quick note:
2^4+2^3+2^2+2^1+2^0 = 15.
4^2+3^2+2^2+2^1 != 15.
(If it is the first, you do need 2^0 because you need to contemplate for odd numbers, 2^0 = 1. This is how we get odd numbers in binary.)
In this case, the answer about left shift (lls) is correct. When you left shift a binary number you increase the exponent of base 2 by 1.
so:
0001 = 1
0010 = 2
0100 = 4
1000 = 8
These summed give you 15.
So you could shift left, and add the result of each shift to a register.

MIPS How to branch to a 32-bit address?

I am trying to branch to an address:
bne $t0, $0, 0x7813a21c
However, this is incorrect because bne only allocates 16-bits to the immediate
How can I branch to a direct 32-bit address? Is there a way to branch from a value in a register?
You have to use JR to jump to an address stored in a register.
To preform this type of operation you will need a jump statement. You have to tell the code to jump control context to the exact line you wish to specify. This is example syntax: j offset Where in your address is the offset.
Here is a link that better reviews what you have to do. Check out the section on jump. These are the types of jump available. One of them is what you need: j offset, jal offset, jr $rs, jalr $rs
Here is the link:
http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/jump.html
Good luck
We can load 32-bit addresss to the register (e.g. $t1) in 2 steps:
Load the upper 16 bits by lui (Load Upper Immediate).
Load the lower 16 bits by ori (Or Immediate).
NOTE: It is work because lui fills the lower 16 bits with 0s, so bitwise OR load the lower 16 bits (n | 0 = n);
In code below if $t0 is equal to 0 we do skip jr instruction.
Or if $t0 is not equal to 0 we do not skip jr instruction (or we do jump).
beq $t0, $0, SKIP
# load 0x7813a21c to $t0
lui $t1, 0x7813 # load the upper 16 bits
# Now $t1 = 0x78130000
ori $t1, $1, 0xa21c # load the lower 16 bits
# Now $t1 = 0x7813A21C
jr $t1 # as #Matt Eckert said
SKIP: