0

I wrote this function to convert an int value to ascii string. But when the input is something like 315 it'll print 31 into the string. As I'm not an expert in assembly any help with this will appreciate. Here's the code: (int_buf is where the integer input is stored, $a is the string output)

 itoa:
  la      $t0, int_buf   # load buf
  add     $t0, $t0, 30   # seek the end
  sb      $0, 1($t0)     # null-terminated str
  li      $t1, '0'  
  sb      $t1, ($t0)     # init. with ascii 0
  li      $t3, 10        # preload 10
  beq     $t8, $0, iend  # end if 0
loop:
  div     $t8, $t3       # a /= 10
  mflo    $t8
  mfhi    $t4            # get remainder
  add     $t4, $t4, $t1  # convert to ASCII digit
  sb      $t4, ($t0)     # store it
  sub     $t0, $t0, 1    # dec. buf ptr
  bne     $t8, $0, loop  # if not zero, loop
  addi    $t0, $t0, 1    # adjust buf ptr
iend:
  move    $a1, $t0       # return the addr.
  jr      $ra            # of the string

EDIT: I fount out the problem is not in the function, as it's in the way I print the string to a file afterwards:

li    $v0, 15
move  $a0, $s6      
move  $t8, $s2
jal   itoa
li    $a2, 4 //problem was only 2 digits selected here!
syscall

How can I prevent the tool from printing empty chars into my file when I set it to a default of 4 digits?

pike93
  • 1
  • 3
  • Looks like $t8 is the integer input, $a1 is the address of the output ASCII string. Do you have a debugger where you can single step this code? – amdn Jan 19 '16 at 08:38
  • Yes, when at 'mflo $t8' $t8 has a value of 27, which is the int value given to function in this case. – pike93 Jan 19 '16 at 08:57
  • If the input is 27 (decimal) then at mflo (Move From LO, the quotient after division by 10, which is in $t3) register $t8 will still be 27... step one instruction (the mflo) and register $t8 should contain the quotient (2 decimal). – amdn Jan 19 '16 at 09:02
  • _"when the input is something like 315 it'll print 31 into the string"_ I'm unable to reproduce this with PCSpim. If I enter 315 I get 315 as the output. Please post a complete minimal example that can be used to reproduce the problem. – Michael Jan 19 '16 at 09:36
  • When the function returns both $a1 and $t0 will have the address in memory of the string. If the input is 315 decimal you should see 0x33 0x31 0x35 0x00 in consecutive bytes in memory at the address in $t0. Those correspond to the ASCII values for '3', '1', '5', and the null terminator. – amdn Jan 19 '16 at 09:49
  • The problem is not in the function, as Michael said. Thank you both for your help :) – pike93 Jan 19 '16 at 09:52
  • No problem. If the syscall needs the number of bytes in $a2, then you shouldn't hard code it to 4. Two options: (1) change itoa function so it puts the length in $a2 or (2) compute the length after itoa returns. – amdn Jan 19 '16 at 09:57
  • Yeah but that's the point. How can I get the "length" of an integer value? – pike93 Jan 19 '16 at 10:00
  • Well, in itoa function you know that $t0 points to the first valid character (byte) of the string and you know the string is right justified in a 32 byte buffer, int_buf. So the length of the string is int_buf + 32 - $t0 (including the null terminator byte). – amdn Jan 19 '16 at 10:06

1 Answers1

2

How can I prevent the tool from printing empty chars into my file when I set it to a default of 4 digits?

Calculating the number of digits in the string is easy. You know that the NUL-terminator characters is at int_buf+31 because of how itoa is written. So just take the difference between that and the address you get back from itoa:

li $a2,int_buf+31
sub $a2,$a2,$a1  # a2 is now equal to the number of digits in the string
Michael
  • 57,169
  • 9
  • 80
  • 125
  • You could try using `la` instead of `li`. It works fine with `li` in PCSpim anyway. – Michael Jan 19 '16 at 10:11
  • That's probably why itoa did that in two steps (limitation of the assembler?)... la $t0, int_buf # load buf add $t0, $t0, 31 # point to null byte – amdn Jan 19 '16 at 10:11
  • @amdn should I use $t0 in li then? – pike93 Jan 19 '16 at 10:22
  • The register you use should be of no importance, except that you have one of the operands in `$a1` (the address returned by `itoa`), and you presumably want the result in `$a2`. So it seems easiest to me to just use those two registers for this calculation. – Michael Jan 19 '16 at 10:26
  • @pike93, sorry for the confusion, like Michael said you can just use $a2 – amdn Jan 19 '16 at 10:30
  • The problem is that I can't use a variable in li, because the then QtSpim gives me a syntax error. – pike93 Jan 19 '16 at 10:57