What am I doing wrong when converting these lines of C++ into assembly/mips?

Tags: c++ assembly mips
By : okmanl
Source: Stackoverflow.com
Question!
for(int i = 0; i < 6; i++) {
   int temp = pos[i];
   x[temp] = data[i];
}

Let's say I've already created the arrays in mips, then,

main:   la  $s1, x ## load address of x into $s1
la      $s2, pos  # load address of pos into $s2
la      $s3, data # load address of data into $s3 
li      $s6, 6 # for loop test. 
li  $s0, 0 # i variable

This is how I tried translating the two lines of C++ into mips,

add     $t1, $s2, $s0 #  Get pos[i] and put in $t1;
sw      $t1, ($t3) # int temp = pos[i] 

add     $t2, $s3, $s0 # Get data[i] and put in #t2
add $t4, $s1, $t3  # Get x[temp] and store it in $t4
sw      $t2, ($t4)  #      x[temp] = data[i];   

addi    $s0, $s0, 1 #   i++ 
blt     $s0, $s6, for # (for i < 6)

However when I run this on qtspim (when combined with the full code) the output I end up getting is

0 0 0 0 0 0 0 0 0 0

Instead of

0 73 0 47 0 0 23 0 0 26

Which is what I sould be getting... What am I doing wrong? Thanks.

By : okmanl


Answers

You had some of the basic structure correct and had good comments.

But, there were some bugs with unitialized values, using the wrong register and not actually fetching from memory. Also, index values must be converted to byte offsets.

I've produced two versions of your program. A version with annotations for the bugs. And, a cleaned up and working version.


Here is the annotated version [please pardon the gratuitous style cleanup]:

 main:
    la      $s1,x                   # load address of x into $s1
    la      $s2,pos                 # load address of pos into $s2
    la      $s3,data                # load address of data into $s3
    li      $s6,6                   # for loop test.
    li      $s0,0                   # i variable

    # This is how I tried translating the two lines of C++ into mips,

for:
    # NOTE/BUG: for the index values, when adding them to the base address
    # of a given array, we need a _byte_ offset (i.e. the index multiplied by
    # 4)

    # NOTE/BUG: this does _not_ fetch pos[i] from memory -- it merely puts "i"
    # into the target
    add     $t1,$s2,$s0             #  Get pos[i] and put in $t1;

    # NOTE/BUG: $t3 is never initialized to anything
    sw      $t1,($t3)               # int temp = pos[i]

    # NOTE/BUG: this does _not_ fetch pos[i] from memory -- it merely puts "i"
    # into the target
    add     $t2,$s3,$s0             # Get data[i] and put in #t2

    # NOTE/BUG: $t3 should contain an _index_ value -- it would have to be
    # multiplied by 4 to create a _byte_ offset
    add     $t4,$s1,$t3             # Get x[temp] and store it in $t4
    sw      $t2,($t4)               #      x[temp] = data[i];

    addi    $s0,$s0,1               #   i++
    blt     $s0,$s6,for             # (for i < 6)

Here is the cleaned up version. I added the missing code to make it a whole runnable program. I tried to keep as much of your original code as possible, but, unfortunately, I had to refactor it:

    .text
    .globl  main
#
# for (int i = 0;  i < 6;  i++) {
#   int temp = pos[i];
#   x[temp] = data[i];
# }
main:
    la      $s1,x                   # load address of x into $s1
    la      $s2,pos                 # load address of pos into $s2
    la      $s3,data                # load address of data into $s3
    li      $s6,6                   # for loop test.
    li      $s0,0                   # i variable

    la      $a0,msg_pos
    move    $a1,$s2
    jal     print

    la      $a0,msg_data
    move    $a1,$s3
    jal     print

for:
    sll     $t0,$s0,2               # get byte offset for pos/data

    addu    $t1,$s2,$t0             # get address of pos[i]
    lw      $t1,0($t1)              # get value of pos[i] (i.e. temp)

    bltz    $t1,next                # skip negative indexes
    bge     $t1,6,next              # skip indexes that overflow

    sll     $t1,$t1,2               # convert temp to byte offset
    addu    $t1,$s1,$t1             # get address of x[temp]

    addu    $t2,$s3,$t0             # get address of data[i]
    lw      $t2,0($t2)              # get value of data[i]

    sw      $t2,0($t1)              # x[temp] = data[i]

next:
    addi    $s0,$s0,1               # i++
    blt     $s0,$s6,for             # (for i < 6)

    la      $a0,msg_x
    move    $a1,$s1
    jal     print

    li      $v0,10
    syscall

# print -- print array
#
# arguments:
#   a0 -- message pointer
#   a1 -- array pointer
print:
    li      $a2,6

    li      $v0,4
    syscall

print_loop:
    li      $v0,4
    la      $a0,msg_space
    syscall

    li      $v0,1
    lw      $a0,0($a1)
    syscall

    addiu   $a1,$a1,4
    addi    $a2,$a2,-1
    bgtz    $a2,print_loop

    li      $v0,4
    la      $a0,msg_nl
    syscall

    jr      $ra

    .data
pos:    .word   5, 0, 4, 1, 3, 2
data:   .word   1, 2, 3, 4, 5, 6
x:      .word   -1, -1, -1, -1, -1, -1

msg_pos:    .asciiz     "pos:"
msg_data:   .asciiz     "data:"
msg_x:      .asciiz     "x:"
msg_space:  .asciiz     " "
msg_nl:     .asciiz     "\n"

Edit: Although not part of your original code, I added a bounds check on temp as it was a part of a similar question asked and makes good sense anyway.



It looks like a strange issue.

For now, I can suggest you do the following things:

  • Check if your *.jar file is executable. Type sudo chmod +x /opt/xxxx/xxxx-0.0.1.jar to be sure about that and start service again.
  • Try to copy *.jar file to /etc/init.d/ directory instead of creating link. Type cp /opt/xxxx/xxxx-0.0.1.jar /etc/init.d/ and start service again.

Let me know if it helped. If not, maybe we can figure out a different solution.

Regards



This video can help you solving your question :)
By: admin