confusion in MIPS storing bits, - binary

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.

Related

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.

How to return to a specific point in a MIPS program

I am writing a function in MIPS that will divide two fractions stored in the a0-a3 registers, like so: (a0/a1) and (a2/a3). I already have a function that will multiply both fractions together, so all I need to do is switch the numerator and denominator on the second fraction and call my multiplication function. I have that part figured out, however I also need to make sure that the numerator retains the sign, meaning that if I flip the second fraction around, and it's a negative, then I need to multiply both the numerator and the denominator by -1. I have written a separate function to do this for me, but after calling that function I don't know how to jump back to where I was. Here is the code:
f_div:
#Flip the second fraction (a2/a3) -> (a3/a2)
add $t0, $a2, $0
add $a2, $a3, $0
add $a3, $t0, $0
ble $a3, $0, f_flipsign #Branch if $a3 <= 0
#I need to be able to jump back here from f_flipsign
#How do I arbitrarily jump back to a location in the program without
#direct access to the PC?
add $s0, $ra, $0 #Save $ra so I don't lose it when I jal f_mul
jal f_mul
add $ra, $s0, $0 #Put the original $ra back
# Also, is there a better way to do this ^
jr $ra #Jump back to main
f_flipsign:
li $t0, -1
mult $a2, $t0
mflo $a2
mult $a3, $t0
mflo $a2
jr ? #How do I make this jump back to the middle of f_div?
I have researched and studied for hours today and I can't seem to figure this out. I understand how these instructions are formatted, I just need to know how to accomplish this one thing. Any help is greatly appreciated, thank you for taking your time.
If your f_flipsign subroutine is in fact some code you just need to execute only in that case, then maybe it does not have to be a subroutine at all and just change the branch condition and add the flip sign code there.
In that case, just change the ble to a bgt to skip the flip code, e.g.:
bgt $a3, $0, dont_flip #Branch if $a3 > 0
# Your code to flip sign
li $t0, -1
mult $a2, $t0
mflo $a2
mult $a3, $t0
mflo $a2
dont_flip:
# Code continues here (whether it flipped sign or not)
If flip_sign is a subroutine that may be called from many places, then you should use jal-code-jr, but you have to preserve $ra somewhere (usually the stack) so that it is not lost when calling the subroutine.
Assuming you have preserved $ra, then you would write something like this:
bgt $a3, $0, continue #Branch if $a3 > 0
jal f_flipsign
continue:
# Code continues here (whether it flipped sign or not)
and in your f_flipsign subroutine end with:
jr $ra

MIPS, using a while loop to calculatethe sum of odd integers 1-9

The following is my code in MIPS to calculate the sum of odd integers using a while loop.
.data
num: .space 4
.text
.globl main
main:
li $t1, 1
li $t2, 9 # make $t2 9 to break the loop
li $t3, 1
loop:
beq $t3, 11, Exit # check to see if $t3 = 11 if so exit
addi $t3, $t3, 2 # change $t3 to next odd number by adding 2
add $t1, $t1, $t3 # add $t3 to $t1 (1+3,...3+5...etc...)
j loop #jump back to the start of the loop
Exit:
li $v0, 1 # system call code to print an int
lw $a0, num # address of int to print
syscall # print the int
jr $ra #exit
This is my first real experience with MIPS and I'm not sure what is going wrong in this code. I put the print inside the while loop to see if it was ever calculating, but the result is always 1.
So, my result at the end is just 111111.
Edit: Removed the prints inside of the loop with the same result.
And OS is Windows 7 64x
Update: Having num as a variable was over complicating things. Code has been revised as follow and works. Thank you for the help!
enter code here
.data
.text
.globl main
main:
addi $t1, $0, 1
addi $t2, $0, 3
loop: bge $t2, 11, Exit # check to see if $t3 >= 11 if so exit
add $t1, $t1, $t2 # add $t2 to $t1 (1+3,...3+5...etc...)
addi $t2, $t2, 2 # change $t2 to next odd number by adding 2
j loop #jump back to the start of the loop
Exit:
li $v0, 1 # system call code to print an int
move $a0,$t1 # address of int to print
syscall # print the int
jr $ra #exit
la $t1, num
You're clearly getting into trouble here, since you're overwriting your accumulator with the address of num every time you're making the syscall. You're losing the current state of your calculation each time.
You'll need to either save your registers, or simply use different ones. Since I don't know what OS it is that you're using, I don't know if you more generally need to save registers over a syscall, but that could also be a source of errors.
I did similar problems for an architecture class and this seemed to be a recurrent problem among all students. When facing problems similar to this our professor's recommendation was to use a different register to temporarily store the register's address to avoid overwriting other desired values from our most commonly used regs.

Checking even or odd on mips using Shift operators and bne

I know I can check whether an integer is even if I shift right by 1, then shift left by 1 and the number stays as the original number.
My code isn't working as intended. This is my first time using MIPS and any help would be appreciated. I want to let the user input any number and my code will tell the user whether it is an even number.
.data
msg: .asciiz "even"
.text
.globl main
main:
li $v0, 5
syscall
or $t0, $0, $v0 # Register $t0 gets input
srl $t1 , $t0 , 1 #shift right by 1
syscall
sll $t1 , $t0 , 1 #shift left by 1
syscall
bne $t1, $t0, msg # if t1 equals t2 then it prints out even
syscall
There are a couple of strange things you're doing, and one easy-fix bug. But until you get the strange things fixed, you're going to be hozed.
First, like #markgz said, what are those syscalls supposed to be doing? Get rid of all of them except the one where you're getting a value from the user. Otherwise, you're going to get a number from the user over and over.
Second, branching to msg makes no sense. The memory at msg is an ASCIIZ string containing the characters m, s, g, and \0. These are not the 32 bits you are looking for. You need to branch to an instruction. I'm going to assume that labels isEven and isOdd exist somewhere.
The bug is what #Konrad said. Omitting the strange syscalls, your code is doing this:
srl $t1, $t0, 1 # shift *original val* right by 1 *and put in $t1*
sll $t1, $t0, 1 # shift *original val* left by 1 *and put in $t1*
bne $t1, $t0, isOdd # *will always be true because we just changed $t1 to be <> $t0*
So if you follow #Konrad's suggestion, it would look like this:
srl $t1, $t0, 1 # shift *original val* right by 1
sll $t1, $t1, 1 # shift *modified val* left by 1
bne $t1, $t0, isOdd # *Now we know if the value changed*
Note that I'm branching to isOdd. You claimed that if the values are different, then the number is even. That's incorrect.
As an aside, my favorite way to do this would be a little bit different:
andi $t1, $t0, 0x01
beq $t1, $zero, isEven
I'll leave it to you to figure out what I'm doing. One thing about your method: it fails if the most significant bit is set (which it will be if it's a negative signed integer).
There are so many bugs in your code.
srl $t1 , $t0 , 1 #shift right by 1
syscall # why you are using syscall here ??
sll $t1 , $t0 , 1 #shift left by 1--and should be sll $t1, $t1, 1
syscall #and why also here ??
bne $t1, $t0, msg #wrong ,here you need to pass label as third operand for offset
li $v0,4 # code 4 == print string
la $a0,string # $a0 == address of the string
syscall
Note: in spite of this you can just do & operation on any data with 0x1 and then check for the result is 0 (even) or 1 (odd)
I want also to share this link for programming tutorial on mips
http://chortle.ccsu.edu/AssemblyTutorial/index.html

MIPS - loading individual bits

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.