MIPS while loop error - loops

I am having some trouble with the following mips code:
li $t0, -1
li $t5, 0
countNumberofVariables:
addi $t0, $t0, 1
beq $t0, $t8, endCount
add $t1, $t0, $t9
lb $t1, ($t1)
li $t2, 10
beq $t1, $t2, endCount
li $t2, 13
beq $t1, $t2, endCount
li $t2, 97
blt $t1, $t2, countNumberofVariables
li $t2, 122
bgt $t1, $t2, countNumberofVariables
li $t2, -1
stackScan:
addi $t2, $t2, 2
add $t3, $sp, $t2
lb $t3, ($t3)
beq $t3, $t1, countNumberOfVariables
li $t4, 64
bne $t4, $t3, stackScan
addi $sp, $sp, -2
sb $t1, ($sp)
li $t1, 0
sb $t1, 1($sp)
addi $t5,$t5,1
j countNumberofVariables
endCount:
move $a0, $t5
li $v0, 1
syscall
j main
What I am trying to do is count the number of unique lower case letters in a string (address in $t9, length in $t8). The problem I am having, when running under SPIM 7.3 is that I get this error:
Instruction references undefined symbol at 0x00400108
[0x00400108] 0x11180000 beq $8, $24, 0 [endCount-0x00400108]; 87: beq $t0, $t8, endCount
The variables are:
$t0, outer loop counter
$t5, number of unique lowercase letters in string
$t1, the character at the current location in the string
$t2, random variable in outer loop, loop counter in inner loop
$t3, the character at the current location on the stack in the inner loop
$t4, random variable
note that the magic constant 64 is a sentinel value at the top of the stack.
EDIT: SOLVED. I changed label names to be shorter, which seemed to satisfy spim. Not quite sure what the underlying problem was, but if you are having a problem where there doesn't seem like there should be one, change to shorter labels

Related

Trying to change array value in MIPS assembly

I was hoping that I could get some help debugging some code. I am going to try to not make this a It is for a MIPS assembly project in recursion. The program is only supposed to print prime numbers.
The idea is I have two arrays, one that lists every whole number up to 110, and the other as a flag array that is initialized to all ones.
For every position in the flag array that is a 1 it prints the number and every 0 it doesn't print the number. The good news is I figured out issues with all my loops, the issue I am having is saving the value 0 to the flag array at the position it currently is. Everything that I reference talks about using:
sw [register], ([register])
From what I understand that is how you save the contents of one register to the position of the other? It doesn't seem to work for me. I went ahead and posted the code down bellow, It is kind of messy and really long, but my code for recursion is down where it says Eratosthenes.
.data
NUM_ARRAY: .space 800 # 800-byte memory space
FLAG_ARRAY: .space 800 # 800-byte memory space
START_MSG: .asciiz "The prime numbers up to 110 are:\n"
END_MSG: .asciiz "Completed ...."
SPACE: .asciiz " "
NEWLINE: .asciiz "\n"
BUG1: .asciiz "Out of loop"
INK: .asciiz "incrementK"
INX: .asciiz "incrementX"
.text
.globl main
# THE BEGINNING OF MODULE MAIN #######################
main:
# save the ten registers --------------------------
subu $sp, $sp, 48 # stack frame for 12 registers
sw $ra, ($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $s2, 12($sp)
sw $s4, 16($sp)
sw $s5, 20($sp)
sw $t0, 24($sp)
sw $t1, 28($sp)
sw $t2, 32($sp)
sw $v0, 36($sp)
sw $a0, 40($sp)
# initialize the essential parameters -------------
li $s0, 111 # the largest number (always - 1)
li $s1, 10 # the square-root of $s0 register
li $s2, 2 # the initial value for "k"
li $s4, 0 # the first numbers to consider
li $s5, 1 # '1' - it is a prime number
li $t2, 0 # loop ounter
# show an opening message ---------------------------------
li $v0, 4 # system call #4
la $a0, START_MSG
syscall
# initialize the two arrays -------------------------------
la $t0, NUM_ARRAY # set the address of the 1st array
la $t1, FLAG_ARRAY # set the address of the 2nd array
loop1: sw $s4, ($t0) # load a number
sw $s5, ($t1) # load the initial property (1 - a prime)
addi $t2, $t2, 1 # increase the loop counter by one
beq $t2, $s0, EXIT1 # if all the array elements are set up
addi $s4, $s4, 1 # increase the number by one
addu $t0, $t0, 4 # increase the pointer by four bytes
addu $t1, $t1, 4 # increase the pointer by four bytes
j loop1 # repeat to "loop1"
EXIT1: li $s2, 2
li $s6, 2
jal Eratosthenes # start recursive Eratosthenes
li $v0, 4 # system call #4
la $a0, NEWLINE
syscall
li $v0, 4 # system call #4
la $a0, NEWLINE
syscall
li $t2, 0 # reset the loop counter
la $t0, NUM_ARRAY # reset the address of the 1st array
la $t1, FLAG_ARRAY # reset the address of the 2nd array
loop3: lw $a0, ($t1) # load the number there
beq $a0, $zero, SKIP1 # if the target is '0': skip
beq $t2, $zero, SKIP1 # if repeated enough: skip
li $v0, 1 # system call #1
lw $a0, ($t0) # load the number there
syscall
li $v0, 4 # system call #4
la $a0, NEWLINE
syscall
SKIP1: addi $t2, $t2, 1 # increase the loop counter
addu $t0, $t0, 4 # increase the pointer by four bytes
addu $t1, $t1, 4 # increase the pointer by four bytes
blt $t2, $s0, loop3
li $v0, 4 # system call #4
la $a0, END_MSG
syscall
# restore registers ---------------------------------------
lw $ra, ($sp)
lw $s0, 4($sp)
lw $s1, 8($sp)
lw $s2, 12($sp)
lw $s4, 16($sp)
lw $s5, 20($sp)
lw $t0, 24($sp)
lw $t1, 28($sp)
lw $t2, 32($sp)
lw $v0, 36($sp)
lw $a0, 40($sp)
addu $sp, $sp, 48 # delete the stack frame
jr $31 # park it at the parking spot
# THE END OF MODULE MAIN ##########################################
Eratosthenes:
subu $sp,$sp,36
sw $ra, 0($sp)
sw $t5, 4($sp)
sw $t6, 8($sp)
sw $t0, 12($sp)
sw $t1, 16($sp)
sw $t2, 20($sp)
sw $s4, 24($sp)
sw $s5, 28($sp)
sw $s0, 32($sp)
li $s5, 0 #change s5 to 0
li $s6, 2 #reset the x
li $t2, 0
la $t0, NUM_ARRAY #reset Array 1
la $t1, FLAG_ARRAY #reset Array 2
R_Loop:
mult $s2,$s6
mflo $t7
addi $t2,$t2,1
lw $s4, ($t0)
beq $t7, $s4, SKIPone
beq $t2, $s0, EXITL #branch if counter is max
addu $t0, $t0, 4 #next spot in NUM_ARRAY
addu $t1, $t1, 4 #next spot in FLAG_ARRAY
li $v0,1
move $a0, $t7
syscall
li $v0,4
la $a0, NEWLINE
syscall
li $v0,4
la $a0, NEWLINE
syscall
j R_Loop
SKIPone:
addi $s6,$s6,1 #increment x by one
sw $zero, ($t1) #attempt at making position at array 0
#have also tried
#sw $s5, ($t1) #where s5 is initialized at 0
#please take note that offset is 0, because it needs to be
#at the current position at the array
li $v0,4
la $a0, NEWLINE
syscall
li $v0,4
la $a0, NEWLINE
syscall
li $v0,1
move $a0, $t4 #debug aid
syscall
li $v0,4
la $a0, NEWLINE
syscall
li $v0,4
la $a0, NEWLINE
syscall
beq $t2 $s0, EXITL
li $v0, 4
la $a0, INX #debug aid
syscall
j R_Loop
EXITL:
li $t8,10
li $v0, 4
la $a0, INK #debug aid
syscall
beq $s2,$t8, EXITR
addi $s2,$s2,1 #increment k by one
jal Eratosthenes
li $v0 4
la $a0, BUG1
syscall
EXITR:
lw $ra, 0($sp)
lw $t5, 4($sp)
lw $t6, 8($sp)
lw $t0, 12($sp)
lw $t1, 16($sp)
lw $t2, 20($sp)
lw $s4, 24($sp)
lw $s5, 28($sp)
lw $s0, 32($sp)
addu $sp,$sp,36
jr $ra
Any help is appreciated, nothing else seems to work and my teacher is of no help.

MIPS - Having trouble finding the minimum value in an array

so I've been given an assignment in which I'm supposed to find the index of the max and min values in a user-created 10 digit array in MIPS assembly language. I've been able to find the max value but I'm having trouble finding the min value. I figured it should be a simple solution once I find the max value but I was wrong.
Here is what i have to find the max value:
deleteMax:
# $s7 is the register where the address of the array is stored
# $s0 is the register where the array size is stored
# Clear out unimportant registers
addi $s1, $zero, 0
addi $t0, $zero, 0
addi $s3, $zero, 0
addi $s4, $zero, 0
addi $t6, $zero, 0
addi $t7, $zero, 0
addi $t0, $zero, 0 # Address of first element in bytes
li $t3, -1 # Max index
li $s2, 0 # Max value
li $t1, 0 # Counter
loop:
sll $s1, $t1, 2
add $s1, $s1, $s7
lw $s3, 0($s1) # Load the first element into $s3
li $v0, 1
move $a0, $s3
syscall
slt $t2, $s3, $s2 # If $s3 < $s2, $t2 = 1, if $s3 >= $s2, $t2 = 0
bne $t2, $zero, find_max
ori $s2, $s3, 0 # Updates the maximum value
ori $t3, $t1, 0 # Updates the maximum value index
find_max:
addi $t1, $t1,1 # Increase the counter
bne $t1, $s0, loop # if the counter hasn't reached the end, go
back to the loop
j print_max
This does what I want: Find the max and it's index. However when I try switching these 2 lines of codes:
slt $t2, $s3, $s2 # If $s3 < $s2, $t2 = 1, if $s3 >= $s2, $t2 = 0
bne $t2, $zero, find_max
to lets say:
slt $t2, $s3, $s2 # If $s3 < $s2, $t2 = 1, if $s3 >= $s2, $t2 = 0
bne $t2, 1, find_max
The min value comes out to 0?
I'm not sure why this is happening and unsure what I can do for my current situation to find the min value.
I hope I've explained myself and my code + comments have explained the situation enough. Im more than happy to answer any more confusion you guys may have.

Copy array elements to another array in MIPS assembly

i have to make a program that fills an array with 30 integers entered from keyboard.Then the user type 'c' to copy the array to an other array.i've done with the first step but i cant manage to copy the array to another.
Here is my code
.data
msg1: .asciiz "> "
msg2: .asciiz "type 'c' to copy \n>"
.align 2
array: .space 400
.text
main:
la $t3 array
loop:
la $a0, msg1 #output message 1
li $v0, 4
syscall
li $v0, 5 #read integer input
syscall
move $t0, $v0
beq $t0, -99, endloop #loop until user types -99
beq $t1,30,endloop #get user input up to 30 times
addi $t1, $t1, 1 #counter
sw $t0,($t3)
addi $t3,$t3,4
b loop #loop until it reaches 30
endloop:
la $a0, msg2 #output message 2
li $v0, 4
syscall
li $v0, 12 #read character input
syscall
beq $v0, 'c', COPY
j NEXT
COPY:
NEXT:
The most primitive way to do it is to
la $t1, dst_array
la $t3, src_array
addu $t0, $t3, 30*4 # setup a 'ceiling'
copy_loop:
lw $at, 0($t3)
sw $at, 0($t1)
addu $t1, $t1, 4
addu $t3, $t3, 4
blt $t1, $t0, copy_loop # if load pointer < src_array + 30*4
However, some implementations of MIPS don't use forwarding, and therefore you have to wait until $at is written back. For that purpose, there may be either a stall (which you could get rid off)
subu $t1, $t1, 4
copy_loop:
lw $at, 0($t3)
addu $t1, $t1, 4
addu $t3, $t3, 4
sw $at, 0($t1)
or a load delay slot, which usually takes 1 cycle, making it
copy_loop:
lw $at, 0($t3)
addu $t1, $t1, 4
sw $at, 0($t1)
addu $t3, $t3, 4
Generally speaking, it depends :)

Array sorting in MIPS

So I am working on an assignment to sort an array in MIPS. The data to sort is given in a separate .asm file as follows:
.data
.word 3
.word 40
.word 30
.word 70
.text
I decided to use bubble sort. I am fairly certain that my algorithm is sound, and it appears to sort the data correctly. The fun thing about this project is that the values we sort will be played as MIDI notes as a means of testing the program (so, naturally, the notes should play in ascending order). This is working pretty well when I test my code, however, I'm hearing a few strange beats at the end of the MIDI notes. I stepped through my code and discovered that, at the end, $t1 (the value I use to compare to my loop iterator for completeness) holds a value of 7, when I expected it to hold a value of three. I assign $t1 as 0($t2), $t2 is 0x10010000 which I assume is still the base address of my array. The base address of the array should hold 3, shouldn't it?
I'm a little confused about why $t1 is 7 at all... any advice? I have included all of my code below.
#ec2.asm
.include "ec2_data.asm" #must be in the same directory as ec2.asm
#ec2_data.asm: puts some values in the "data segment"
#the first value is the number of values to sort (n)
#the remaining n word values are the data to sort
#the values will be stored in memory as word values starting
# address 0x10010000
j main
#$t2 is hasChanged
#$t3 is itemCount
#$t4 is i, our iterator in the for loop
#$t5 is array[i] (temp)
#$t6 is array[i+1] (temp)
while_label:
beq $t2, $zero, done_sorting #checks to see if the previous iteration switched any values. If not, we are done.
addi $t2, $zero, 0 #initialize hasChanged to 0
addi $t3, $t3, -1 #decrement itemCount by -1
addi, $t0, $t0, 4 #add 4 to the array offset
addi, $t4, $zero, 0 #set our for loop iterator to 0
for_label:
lw $t5, 0($t0) #set a temp value equal to array[i]
lw $t6, 4($t0) #set a temp value equal to array[i+1]
beq $t4, $t3, while_label #for loop: if i = itemcount, we have incremented all the way through our for loop
bge $t6, $t5, skip_swap #if array[i+1] is greater than or equal to array[i], we don't need to swap these values
#swap
sw $t6, 0($t0) #set array[i] equal to array[i+1]
sw $t5, 4($t0) #set array[i+1] equal to the temp value
addi $t2, $t2, 1 #set hasChanged to 1 to indicate that a swap has been made
skip_swap:
addi, $t4, $t4, 1 #increment i by 1 (for loop iterator)
j for_label #keep the for loop going!
main:
#read values
addi $t0, $zero, 0x10010000 #sets $t0 to be the base address of the array
addi $t2, $zero, 1
lw $t3, 0($t0) #stores n in $t3
j while_label
done_sorting:
# adapted from MIDI example
#duration 25 ms
#instrument (whichever)
#volume 64
addi $v0, $zero, 33 # midi out synchronous
addi $t2, $zero, 0x10010000 # address of original array (which should by now be sorted)
addi $a1, $zero, 250 # duration (ms)
addi $a2, $zero, 1 # instrument
addi $a3, $zero, 64 # volume
addi $t0, $zero, 0 # counter
lw $t1, 0($t2) # end of the loop (should be n)
addi $t1, $t1, 4 # adds four to the array offset in $t1
lw $a0, 0($t2) # stores the first sorted value ( 4($t1) ) in $a0
midi_loop:
beq $t0, $t1, done
addi $t2, $t2, 4
lw $a0, 0($t2)
syscall
addi $t0, $t0, 1
j midi_loop
done:
#addi $v0, $zero, 10 # syscall for exit
#syscall # clean exit
Your sorting algorithm is quite broken. You haven't noticed that because it happens to get the right answer with your test data. It will produce the wrong answer with other test data (e.g. I believe your algorithm will sort 70, 40, 30 to 40, 30, 70).
But your question was about why $t1 ends up with value 7. The answer is simple. You wrote this:
addi $t2, $zero, 0x10010000 # address of original array (which should by now be sorted)
addi $a1, $zero, 250 # duration (ms)
addi $a2, $zero, 1 # instrument
addi $a3, $zero, 64 # volume
addi $t0, $zero, 0 # counter
lw $t1, 0($t2) # end of the loop (should be n)
addi $t1, $t1, 4 # adds four to the array offset in $t1
We can see that you set $t2 to 0 + 0x10010000 = 0x10010000. Then you load the word at 0($t2) (= 0x10010000) into $t1. The word at 0x10010000 is 3, so at that point $t1 is 3. Then you add 4 to $t1, storing the result in $t1. At that point $t1 is 7. You never modify $t1 after that.
SO I really shouldn't have asked this question without giving my code another once-over. The errors were extremely simple. This appears to work.
#ec2.asm
.include "ec2_data.asm" #must be in the same directory as ec2.asm
#ec2_data.asm: puts some values in the "data segment"
#the first value is the number of values to sort (n)
#the remaining n word values are the data to sort
#the values will be stored in memory as word values starting
# address 0x10010000
j main
#$t2 is hasChanged
#$t3 is itemCount
#$t4 is i, our iterator in the for loop
#$t5 is array[i] (temp)
#$t6 is array[i+1] (temp)
while_label:
beq $t2, $zero, done_sorting #checks to see if the previous iteration switched any values. If not, we are done.
addi $t2, $zero, 0 #initialize hasChanged to 0
addi $t3, $t3, -1 #decrement itemCount by -1 WHY
addi, $t0, $zero, 0x10010000 #add 4 to the array offset
addi, $t4, $zero, 0 #set our for loop iterator to 0
for_label:
addi, $t0, $t0, 4
lw $t5, 0($t0) #set a temp value equal to array[i]
lw $t6, 4($t0) #set a temp value equal to array[i+1]
beq $t4, $t3, while_label #for loop: if i = itemcount, we have incremented all the way through our for loop
bge $t6, $t5, skip_swap #if array[i+1] is greater than or equal to array[i], we don't need to swap these values
#swap
sw $t6, 0($t0) #set array[i] equal to array[i+1]
sw $t5, 4($t0) #set array[i+1] equal to the temp value
addi $t2, $t2, 1 #set hasChanged to 1 to indicate that a swap has been made
skip_swap:
addi, $t4, $t4, 1 #increment i by 1 (for loop iterator)
j for_label #keep the for loop going!
main:
#read values
addi $t0, $zero, 0x10010000 #sets $t0 to be the base address of the array
addi $t2, $zero, 1
lw $t3, 0($t0) #stores n in $t3
j while_label
done_sorting:
# adapted from MIDI example
#duration 25 ms
#instrument (whichever)
#volume 64
addi $v0, $zero, 33 # midi out synchronous
addi $t2, $zero, 0x10010000 # address of original array (which should by now be sorted)
addi $a1, $zero, 250 # duration (ms)
addi $a2, $zero, 1 # instrument
addi $a3, $zero, 64 # volume
addi $t0, $zero, 0 # counter
lw $t1, 0($t2) # end of the loop (should be n)
lw $a0, 0($t2) # stores the first sorted value ( 4($t1) ) in $a0
midi_loop:
beq $t0, $t1, done
addi $t2, $t2, 4
lw $a0, 0($t2)
syscall
addi $t0, $t0, 1
j midi_loop
done:

What is this MIPS array + loop doing?

New to MIPS and can understand exactly what is going on with the code, but I do not understand the answer/solution provided. Any help would be greatly appreciated.
Please read the following code and write down the content in array A after funct returns.
.data
A: .word 21,3,2,9,100,22,6,15,33,90
.text
.globl main
main:
la $a0, A
li $a1, 17
li $a2, 10
jal funct
li $v0, 10 # exit
syscall
funct:
li $t0, 0
li $v1, 1000000
funct_L0:
sll $t1, $t0, 2
add $t1, $t1, $a0
lw $t1, 0($t1)
sub $t2, $t1, $a1
bgt $t2, $0, funct_L1
sub $t2, $0, $t2
funct_L1:
bgt $t2, $v1, funct_L2
ori $v0, $t0, 0
ori $v1, $t2, 0
funct_L2:
addi $t0, $t0, 1
blt $t0, $a2, funct_L0
jr $ra
SOLUTION: Finds the smallest difference
It finds the element from the array which is nearest to the number passed in in $a1. In other words, it finds the element x for which the difference abs(x - $a1) is smallest. It returns the index in $v0 and the difference in $v1.

Resources