0

I am building a calculator using MIPS and the result needs to be in floating point round to two decimal places. This is my subroutine for printing out anything into the MIPS display:

mmOut:
lui $t0, 0xffff

mmOutLoop:  

lw      $t1, 8($t0)
andi    $t1, $t1,0x0001
beq     $t1, $zero, mmOutLoop
sw      $a0, 12($t0)    //$a0 has the result I wish to print
jr      $ra //return address of mmOut

Currently I am storing my results (from the calculation) onto a stack and then converting it in to ASCII. How should I implement the same procedure using floating point values?

Michael
  • 57,169
  • 9
  • 80
  • 125
R.I
  • 9
  • 3
  • With MARS simulator you have available [several `syscall` services](http://courses.missouristate.edu/kenvollmar/mars/help/syscallhelp.html). Like `v0 = 2` "print float". But two decimal places => that's a problem. Probably the most accurate *simple* solution (without writing 100% correct `printf`) is to multiply result by `100.0`, round it to integer value, and print it as integer (inserting `'.'` ahead of last 2 digits). This will cut down the available range for results considerably (max value will be `int32_t`/100 = ~21474836 only) and it may produce imperfect results. – Ped7g Dec 08 '17 at 22:36
  • Or write your own `printf` of float values, which is far from trivial (especially if you would also try to make it fast, and 100% correct, you may easily need several days/weeks to implement it). BTW, watch and learn, how fixed output device turns the helper services useless. Would you be able to redirect the output of "print" services to memory instead of console, you would be able to use the "print float" service and then adjust the resulting string in memory to have two decimal places, and print that to screen as string. That would be slightly more code that *100 int, but full float. Pity. – Ped7g Dec 08 '17 at 22:40
  • 1
    That code you posted doesn't make much sense to me, looks like it may even end in infinite loop. – Ped7g Dec 08 '17 at 22:43
  • So you have a spin loop waiting for the low bit of `0xffff + 8` to become zero, then you store a single word to `0xffff + 12`. This has absolutely nothing to do with the problem of converting integers or floating point to strings. Is `$a0` or a single ASCII character? – Peter Cordes Dec 09 '17 at 15:44

1 Answers1

1

As I commented, writing the result to memory-mapped I/O has nothing to do with the problem of float->string conversion. Those are basically two separate steps. For parts of the algorithm that generate results in printing order, you could send them to MMIO directly instead of storing to a string in memory if you want.

This could overlap time spent calculating with time spend waiting for the low bit of 0xffff + 8 to become zero, which apparently means the MMIO register at0xffff + 12 is ready to accept another store, according to the loop in your code.


Related: How to input and output real numbers in assembly language. I only answered the input (string->float) part, unfortunately.

float->string may be easier. Probably you want to split into integer and fractional parts.

Get the integer part (as a float, in case it's too big for a 32-bit integer) and maybe divide by a large power of 10 until it fits in an int. Then you can convert to int and use a fast integer conversion for that chunk of digits. I guess use an FP remainder / modulo calculation to get the least significant part of the integer part, if you had to divide by 10^9 or something to make it fit. (It may take more than one division by 10^9 to get it down to fitting in 2^32).

For the fractional part, implement this in asm:

print a '.'
while(frac != 0) {
    frac *= 10.0;
    double intpart = floor(frac);  // or trunc, frac should be non-negative
    frac -= intpart;
    store or print intpart (as a single ASCII decimal digit)
}

You probably want to use a counter to limit the number of digits printed (because it could be an infinite .999999... or something, I think).

Use a do{}while structure if you always want to print .0 instead of just . when there's no fractional part.

Most FPUs directly support all of those operations with a single instruction. I'm not familiar with MIPS's FPU instruction, but I assume floor or trunc are available in hardware at least by converting to integer and back.


You could make this faster by multiplying by frac by 100 or 10000 and using faster integer stuff. (A 2-digit integer can be split up quickly using a multiplicative inverse with an integer multiply.)

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