Search code examples
assemblymipsruntimeexception

How can I create a double array in MIPS assembly language?


I am new to MIPS assembly. I am trying to convert a java code to MIPS code but I can't figure it out that how can I load and store double values in MIPS. I get this error "address not aligned on doubleword boundary 0x10010001". Here is the java code:

double[] numbers = {1.0,1.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
int i = 0;
while (numbers[i+1] < 150){
 numbers[i+2] = numbers[i+1] + numbers[i];
 i++;
}
for (int j = 0; j < 14; j++){
 System.out.println(numbers[j]);
}

Here is the code that I wrote:

.data

numbers: .double 1.0 ,1.1 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 , 0.0
doublezero : .double 0.0

.text

la $a1 numbers
add $t1 $zero 0 # i = 0 
add $t7 $zero 0 # j = 0
ldc1 $f0 doublezero

while : sll  $t3 $t1 2     #get the offset (i*4)
    add  $t4 $t3 $a1   #t4 is the address for numbers[i]
    add $t5 $t4 1  # t5 = [i+1] 
    l.d $f2 0($t5)  # s5 = current numbers[i+1]
    add $t6 $t4 2  # t6 = [i+2]
    add $a2 $zero 150 # a1 = 150
    l.d $f4 0($t6)  #s6 = current numbers[i+2]
    l.d $f6 0($t4)  # s4 = numbers[i]
    slt $t2,$s5,$a2      # checks if $s5 > $a1  ==> numbers[i+1] < 150
    beq $t2 $zero EXIT       # if t2 = 1 jump exit
    add.d $f4 $f2 $f6   #numbers[i+2] = numbers[i+1] + numbers[i]
    addi $t1 $t1 1 #i++
    j while
    
loop: addi $a3 $zero 14
      slt $s7 $t7 $a3   # checks if $t7 < 14   ==> numbers[j+1] < 150
      beq $s7 $zero EXIT  # if s7 = 1  jump exit
      sll  $t8 $t7 2  #get the offset (j*4)
      add  $t9 $t8 $a1   
      l.d $f8 0($t9)   # t0 = numbers[j]
      ##print
      li $v0 2
      add.d $f12 $f8 $f0
      syscall
      addi $t7 $t7 1 #j++
              

Solution

  • Use syscall function code 3 to print doubles (not function code 2 — that's for single float).

    Use mov.d to copy one register to another, e.g. into $f12 for sycalls (then no need to load 0.0 into $f0).

    (Also, use l.d instead of ldc1.)

    The loop: loop isn't a loop (there is no backward branch for it).

    As @Peter says, your scaling/offsets are not properly accounting for the size of double, which is 8.  Scaling needs to multiply by 8 (shift by 3, not 2), and offsets need to be multiples of 8.

    Your first loop, when its done, should not EXIT the program but rather continue with the next statement (i.e. the printing loop).

    For this statement numbers[i+2] = numbers[i+1] + numbers[i]; there are two loads and one store as array references, whereas the assembly code is doing 3 loads and no store.

    You use $s5, but never put anything in it.

    The comparison of numbers[i+1] < 150 has to be done in (double) floating point, whereas the assembly code is attempting this in integer registers.

    Floating point comparison is done using c.eq.d, c.lt.d, or c.le.d.  Like with integer compares, constants need to be in registers before the compare instruction.  150.0 would best come directly from memory (as a double constant) before the loop and remain there for the loop duration (or you can move integer 150 into a floating point register and convert that to double (cvt.w.d)).

    Conditional branches on floating point compare conditions use either bc1t or bc1f (depending on the sense you want).


    The C-like pseudo code probably doesn't run properly.  The exit condition for the first loop is suspect — it will probably run off the end of the array (depending on its initial data values).

    Translating non-working C code into assembly is a recipe for frustration.  Suggest getting it working in C first; run it to make sure it works.