0

I am creating a program for a user to enter an integer and then check each bit and count how many 1's is in it's binary value. So if I input 4673 I should get "4" as an output because there is 4 ones. This is the code I have below, for some reason I am only getting "0" as an output. My guess is I am not properly loading each bit with the "andi" and "srl". I check it step by step and when it comes to andi and srl $t0 never holds a value of 1, so I must not be shifting bit by bit?

 .data
Msg: .asciiz "Enter an integer: "



.text
 # Print the first message
 li $v0, 4
 la $a0, Msg
 syscall

 # Prompt the user to enter the first integer
 li $v0, 5
 syscall

 # Store the first integer in $t0
 move $t0, $v0

 addi $t3, $zero, 1

main:
 bgt $t3, 31, exit
 addi $t3, $t3, 1
 andi $t0, $v0, 1
 srl $t0, $t0, 1
 bne $t0, $zero, count 
 j main


count:
 addi, $t1, $t1, 1
 # Shift to the next bit and then go back to main
 j main
 
exit:

# Tell the interpreter to get read to print an integer
 li $v0, 1
 add $a0, $zero, $t1
 
 #Print the integer
 syscall
 
 # End the program
 li $v0, 10
 syscall
  • Ok, try the smallest possible input, e.g. 1, and use single step debugging to see where it goes wrong. – Erik Eidt Mar 14 '22 at 04:18
  • I did, for some reason it never gets set to 1. The andi sets it to 1 but once it goes to srl it sets it to 0 every time. – Java_Assembly55 Mar 14 '22 at 04:30
  • "for some reason it never gets set to 1". Carefully examine each instruction and its effect. The problems should be visible to you in single step debugging. On MIPS, each instruction is simple and straightforward and unsurprising, but if you have a typo somewhere your program won't work. – Erik Eidt Mar 14 '22 at 15:06

1 Answers1

2

You've got this instruction andi $t0, $v0, 1 in your loop. But $v0 never changes within the loop, so you're always getting the same value. And regardless of whether that values was 0 or 1, it's going to be 0 after the srl on the following line.

The whole bit-counting loop could be replaced by something like this:

li $t1, 0  # number of 1-bits
count_ones:
    andi $t2, $t0, 1            # t2 = input & 1
    addu $t1, $t1, $t2          # count += (input & 1)
    srl $t0, $t0, 1             # input >>= 1
    bne $t0, $zero, count_ones  # loop until no 1-bits left

Note that there are more efficient ways of doing this, without any loops at all. See How to count the number of set bits in a 32-bit integer?

Michael
  • 57,169
  • 9
  • 80
  • 125
  • The `move $t0, $v0` before the loop in the question is pointless; they could just shift `$v0`. That's what I was intending with my choice of examples in [MIPS Assembly converting integer to binary and reading the number of 1's?](https://stackoverflow.com/a/71408954) (which I wrote when that was still a question about the concept of binary numbers, not also a debugging question about code with multiple nonsensical weird things.) And since they want to print it, might as well count into `$a0`. Perhaps they don't realize that `$v0` and `$a0` are general-purpose registers. – Peter Cordes Mar 14 '22 at 10:33
  • BTW, doing `srl` before `addu` would let a classic MIPS assembler with `.reorder` enabled fill the branch-delay slot with the `addu` more easily. (Although a smart one might be able to do that anyway). It would also let a dual-issue in-order machine run the loop at 2 cycles per iteration, even without that reordering by the assembler. But this source ordering is probably more human-readable, keeping the shift and branch together, and keeping the `sum += input & 1` together. – Peter Cordes Mar 14 '22 at 10:42
  • Thank you that worked. Only a few weeks into my Assembly course and loops were only briefly covered so it's still all very confusing to me still. – Java_Assembly55 Mar 14 '22 at 19:33