nathpilland
nathpilland

Reputation: 304

Switching character locations in MIPS Assembly

I'm trying to print out

Hello, world.
ello, world.H
llo, world.He
lo, world.Hel
o, world.Hell
, world.Hello
 world.Hello,
world.Hello,
orld.Hello, w
rld.Hello, wo
ld.Hello, wor
d.Hello, worl
.Hello, world
Hello, world.

using only this string in memory String: .asciiz "Hello, world.". So far this is my code:

    .text
String:    .asciiz "Hello, world."
x:         .float 13

    .data 
Main:       lw $t0,x
            jal PrintString
            li $v0, 10
            syscall

PrintString:    la $a0,String
                li $v0,4
                syscall
                bgtz $t0, MoveString
                jr $ra

MoveString: (CODE)

but I'm not sure what to put in the MoveString label. I need to shift the characters in String by one, and subtract what is in x by 1. I'm not sure how to go about doing this. Thanks for your help!

Upvotes: 1

Views: 5051

Answers (1)

Jeff
Jeff

Reputation: 7674

A couple notes first:

  • You have .text and .data mixed up
  • Go ahead and add a newline to the end of the string, it'll make displaying a bit nicer:

    String:    .asciiz "Hello, world.\n"
    
  • Assuming that 13 is used for the length of the string, you should use an integer instead of a float:

    x:         .word 13
    

Now, onto the problem. There's two ways to do this: 1) rotate the string in-place and call syscall 4 each time, or 2) keep the string as it is and print it one letter at a time, playing with the index instead to achieve the rotation effect. You've chosen method 1, so let's go with that.

Start by writing some pseudocode. You need a subroutine that'll rotate the string stored at $a0 to the left by one letter. Immediately, you should be thinking about some kind of loop that iterates over each letter in the string:

for int index from 0 to 12
    copy letter from (index + 1) to index

But wait: what happens to the first letter? It'll get clobbered. And what happens when we reach the end? We'll copy something outside the bounds of String to the last letter slot. So let's work around it by storing the first letter to a temporary register:

temp = letter[0]

for int index from 0 to 11
    copy letter from (index + 1) to index

letter[12] = temp

That's better; that should do it. Next question: how do we do this in MIPS?

We know that $a0 will hold the address of the string, so let's take that for granted. We need at least one temporary register -- since we're already using $t0 for x, let's use $t1 to hold the first letter:

MoveString:
lb $t1, String

We also need an index register, so let's use $t2 for that. Initialize it to zero:

li $t2, 0

It'd be nice to just increment our address register once for each letter, but we don't want to clobber $a0 because it'll mess up PrintString. So let's copy it to $a1 for our loop:

move $a1, $a0

Lastly, we need to know how long the string is, so let's load another copy of x into $t3:

lb $t3, x
sub $t3, $t3, 1               ; We're only iterating over the first 12 letters,
                              ; since the last letter is done manually with temp

Now we can start the loop. We need to copy the letter (which is just a byte) from $a1 + 1 to $a1:

MoveStringLoop:
lb $t4, 1($a1)                  ; Load the letter from (address + 1)
sb $t4, 0($a1)                  ; Store it to (address)
add $a1, $a1, 1                 ; Increment our address
add $t2, $t2, 1                 ; Increment our index
blt $t2, $t3, MoveStringLoop    ; Loop again if index < (length - 1)

sb $t1, 0($a1)                  ; Copy the temp letter to the end of the string

That should be it. After that, we can decrement x and go back to PrintString:

sub $t0, $t0, 1
b PrintString

This isn't an optimal solution by any means; I'm sure a real compiler and some better coding could get the job done in half the instructions. But since you're learning how to write assembly, don't worry about micro-optimization for now. Here's the final code along with its output:

    .data
String:    .asciiz "Hello, world.\n"
x:         .word 13

    .text 
Main:       lw $t0,x
            jal PrintString
            li $v0, 10
            syscall

PrintString:    la $a0,String
                li $v0,4
                syscall
                bgtz $t0, MoveString
                jr $ra

MoveString:
                lb $t1, String
                li $t2, 0
                move $a1, $a0
                lb $t3, x
                sub $t3, $t3, 1

MoveStringLoop:
                    lb $t4, 1($a1)
                    sb $t4, 0($a1)
                    add $a1, $a1, 1
                    add $t2, $t2, 1
                    blt $t2, $t3, MoveStringLoop

                sb $t1, 0($a1)

                sub $t0, $t0, 1
                b PrintString

Output:

Hello, world.
ello, world.H
llo, world.He
lo, world.Hel
o, world.Hell
, world.Hello
 world.Hello,
world.Hello,
orld.Hello, w
rld.Hello, wo
ld.Hello, wor
d.Hello, worl
.Hello, world
Hello, world.

Upvotes: 5

Related Questions