-1

I made a program in which I try to display the binary form of a number input by user. But the program isn't doing the masking correctly. What should I do to solve it?

user input in $s0

Loop:

and $t0,$s0,2147483648  // anding it with this number because only its MSB is 1 all other bits are zero

sll $s0,$s0,1

move $a0,$t0

li $v0,1
syscall

beq $t1,31,Exit

addi $t1,$t1,1
j Loop

UPDATE: I modified this code as suggested by dbrank0, but now it displays only one bit instead of 32 bits

Loop:

and $t0,$s0,2147483648

sll $s0,$s0,1

beq $t1,31,Exit

move $a0,$t0

addi $t1,$t1,1

bgtu $t0,0,Check

li $t0,0
j Loop

Disp:
li $v0,1
syscall

j Loop

Check:
li $t0,1

j Disp

It will be a great deal if someone can help me solve this problem.

Regards

Jens Björnhager
  • 5,632
  • 3
  • 27
  • 47
Naruto
  • 1,710
  • 7
  • 28
  • 39
  • The masking is probably done correctly, but before printing out you probably need to convert the bit you want to print into something representable (either 0/1 by shifting it right 31 positions, or into '0'/'1' by shifting adding additional 0x30). – dbrank0 Oct 09 '12 at 07:17
  • Why should i do that. I am displaying the result stored in $t0 which can either be 1 incase MSB of both numbers match and 0 if MSB of both number don't match. – Naruto Oct 09 '12 at 07:26
  • t0 contains either 0 or 0x80000000. If you want to print 0 or 1, you should shift this 31 bits right before printing. (But don't take my word for granted, it's been ages since I programmed MIPS). – dbrank0 Oct 09 '12 at 09:13

2 Answers2

3

Here's a problem:

bgtu  $t0, 0, Check
li    $t0, 0
j     Loop

If it's a zero, it doesn't get displayed because you're jumping to Loop instead of Disp. Oh look, Disp is written immediately after this instruction anyhow! Solution: get rid of the jump altogether.

Here's another problem, as dbrank0 described:

Disp:
li $v0,1
syscall

This will display the contents of $a0 as an integer. But if the bit was a 1, the value of $a0 will be 0x80000000, not 1! When you try to print 0x80000000, it'll treat it as a signed integer and print -2147483648 instead.

Here's another problem:

beq $t1,31,Exit

Firstly, this instruction is in an awkward place. Why are you checking for an exit condition after the and and shift? You should check for it either at the start or the end, not in the middle. Furthermore, you need to check against 32 because there are 32 bits and you check before printing each bit. Currently the last bit will get chopped off as a result.


There's a clever way to make your program do less work than it needs to. Take advantage of the fact that you're displaying from left to right (ie, the most significant bit is being displayed first). When the MSB is set, it can be treated as a negative number in two's complement!

li     $t0, 32
li     $v0, 1

Loop:
bltz   $s0, Bit1
li     $a0, 0
j      Disp

Bit1:
li     $a0, 1

Disp:
syscall

Tail:
subi   $t0, $t0, 1
beqz   $t0, Exit
sll    $s0, $s0, 1
j      Loop

Exit:
Jeff
  • 7,504
  • 3
  • 25
  • 34
  • Usually a conditional branch on each bit is worse for performance. But MIPS has `SLT` Set on less than (signed). (http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html). So `slt $a0, $s0, $zero` to extract the sign bit of `$s0` into the low bit of `$a0` (zero extended). – Peter Cordes Oct 04 '17 at 18:18
0

Given a pointer to the end of a large-enough buffer in $a1, and an input integer in $a0, this function stores ASCII digits to form a string.

This uses an AND to extract the low bit. It works from low to high bits, so we store backwards from the end of a buffer, leaving an ASCII string in printing order.

.globl to_base2_end    # args: (unsigned a, char *buf_end)
to_base2_end:

  # Runs at least once, so we get "0" instead of the empty string for 0
.loop:                           # do {
    andi  $t0,  $a0, 1           #    extract the low bit
    ori   $t0,  $t0, '0'         #    ASCII digit

    addiu $a1,  $a1, -1
    sb    $t0,  ($a1)            #    *--buf = ASCII digit

    srl   $a0,  $a0, 1           #    a0 >>= 1
    bne   $a0, $zero,  .loop     # }while (a0!=0);

    move  $v0, $a1           # return pointer to the first digit
    jr   $ra

Note that this decrements before the first store, so you could pass it a pointer to a '\n' at the end of a buffer.

You can of course inline this loop instead of using it as a callable function. It stops when the integer is zero instead of looping a fixed 32 times, so it doesn't print leading zeros.

This algorithm is the base2 special case of the basic
do { digit = a % base; } while(a /= base);.

If you're going to print the digits in the order they're generated, you can use

    slt   $t0,  $a0, $zero       #    t0 = 0 or 1 = high bit of a0
    sll   $a0,  $a0, 1

This would give you a branchless version of @JeffE's code. But if you care about efficiency, one system call that writes a whole string is much more efficient than 32 system calls to write 32 integers. (And of course real OSes don't have write-int system calls; that's a Mars/SPIM thing.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847