Why am I getting a duplicate main label error? Also why is there no output? - mips

I am working on my first project in mips, trying to print the sum of all the positive numbers in an array. I am now testing my code with QtSpim and have been getting an error saying I am using the main label twice even though there is only one occurrence. There is also no output, regardless of whether or not I include the main label. Here's the code:
.data
A: .word -89, 19, 91, -23, -31, -96, 3, 67, 17, 13, -43, -74
.text
main:
addi $s0, $zero, 0 #set $s0 for sum of positive nums to 0
la $s1, A #set $s1 to array address
addi $t0, $s1, 48 #set $t0 to exit point
while:
beq $s1, $t0, end
lw $t1, A($s1)
slt $t2, $t1, $zero
bne $t2, $zero, else #skips addition step if A at $s1 is negative
add $s0, $s0, $t1
else:
addi $s1, $s1, 4
j while
end:
li $v0, 1
move $a0, $s0
syscall
li $v0, 10
syscall
Sorry if this is bad formatting for mips, I have only ever worked with Java and C++.

there's an error on this line
lw $t1, A($s1)
What I believe you want is
lw $t1, 0($s1)
A positive integer must be in the offset of the lw instruction.
The main label error seems like a rabbit hole as you see no label was used more than once.

Related

MIPS Stack Segment can't be Expanded

I'm writing a function that should return the square root of a perfect square recursively as part of a longer assignment.
I was following this mathematical method before I reverted to an even simpler algorithm to see if the error would repeat itself and it did.
The following code:
.data
prompt: .asciiz "num2sqrt: "
.text
.globl main
sqrt:
# save return address & t0
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t0, 4($sp)
# t0 = n
move $t0, $a0
# a0 = n/2
srl $a0, $t0, 1
jal sqrtRecursor
#restore return address & t0
lw $t0, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
sqrtRecursor:
# save return address & t1
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t1, 4($sp)
# square test
mult $a0, $a0
mflo $t1
beq $t1, $t0, returnAnswer
bne $t1, $t0, newGuess
#restore return address & t1
lw $t1, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
returnAnswer:
move $v0, $a0
newGuess:
# t1 = (((x+1)*guess)/x)/2
# x+1
addi $t1, $t0, 1
# *guess
mult $a0, $t1
mflo $t1
# /x
div $t1, $t0
mflo $t1
# /2
srl $t1, $t1, 1
move $a0, $t1
jal sqrtRecursor
main:
#print "Enter num2sqrt: "
la $a0, prompt
li $v0, 4
syscall
#input num2sqrt
li $v0, 5
syscall
move $s1, $v0
move $a0, $s1
jal sqrt
# print result
move $a0, $v0
li $v0, 1
syscall
# end
li $v0, 10
syscall
returns the following error on QTSpim:
Can't expand stack segment by 12 bytes to 524288 bytes. Use -lstack # with # > 524288
which then hangs the app for a minute or so.
I've double checked that I'm saving and returning all my return addresses and used variables, and also attempted implementing the same algorithm in Java separately (which worked), but have yet been unable to figure out what I need to fix and where.
I've been able to implement a power function before this so I'm not a complete novice and am asking after putting in approximately 5 hours of research and debugging on this.
It could be a stack management problem or an if/else implementation error from the intuition I have about my own code.

Mips Procedure: Infinite for loop and Exception occurred at PC

Seeing the topics on the site, however I was not able to solve my problem. I noticed that the code inside the procedure falls into an infinite for and in QTSpim I saw that the registers involved are $s0, $s1, $t2, and $t4.
After a few cycles then the message Exception occurred at PC then expection 7 Bad data address.
Here is the code, I can not figure out where mistake, I tried to write it without procedure and it works perfectly.
.data
string: .asciiz "Hello Simon"
string2: .asciiz ""
.text
.globl main
Delete_space:
addi $sp, $sp, -16
sw $s0, 0($sp)
sw $s1, 4($sp)
add $t8, $a0, $zero
lenght_string:
lb $t0, 0($t8)
beqz $t0, for #t8 contain the lenght of string
add $t8, 1
j lenght_string
for:
add $s0, $zero, $zero #i=0
add $s1, $zero, $zero #j=0
condition:
slt $t1, $s0, $t8 #i< lenght_string
beq $t1, $zero, endfor
consequence:
add $t2, $t8, $s0
lb $t3, 0($t2)
bne $t3, ' ', op1
beq $t3, ' ', else
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
op1:
add $t4, $a1, $s1
sb $t3, 0($t4)
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
else:
sub $s1, $s1, 1
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
endfor:
#end
lw $s1, 4($sp)
lw $s0, 0($sp)
addi $sp, $sp, 16
jr $ra
main:
la $a0, string
la $a1, string2
jal Delete_space
la $a0, string2
li $v0, 4
syscall
li $v0, 10
syscall
I think you're trying to copy characters from one string to the other, skipping spaces. (Maybe that's not what you're trying to do - unfortunately, I don't have time to trace the code in detail.) I think the problem is that you're copying from your source string into a data area that doesn't belong to you.
Strings aren't handled the same in Assembly as they are in a high-level language. They're nothing but a sequence of bytes - there is no concept of a String that automatically expands to contain what you put in it. And there's no concept of bounds checking.
Look at these string declarations:
.data
string: .asciiz "Hello Simon"
string2: .asciiz ""
What you've done is assigned string to a memory address containing the byte value 'H'. The subsequent memory locations contain 'e', 'l', 'l', 'o', ' ', 'S', 'i', 'm', 'o', 'n', '\0'.
Then, you've assigned string2 to a memory address containing the byte value '\0' (a null terminator).
If you write a byte to the memory address pointed to by string2, it would replace the null terminator. (You would already be in trouble at this point, because the syscall wouldn't know where your string ends.) If you then write another byte to the memory address pointed to by string2 + 1, you are now writing to memory that you didn't allocate to string2. It might belong to some other variable that's being stored - in which case, you just overwrite what was there before. That's a "buffer overflow", and it's how poorly-written programs such as Internet Explorer get exploited by hackers.
If I'm interpreting the purpose of your program correctly, you need to create a buffer for your output that's big enough to hold it. Something like this would work, assuming your output will never be longer than your input:
.data
string: .asciiz "Hello Simon"
string2: .asciiz "xxxxxxxxxxx"

Attempt to execute non-instruction in mips assembler?

.data
stack: .word 3, 2
.text
.globl main
main:
la $s1, stack #assign stack start memory to $s1
addi $t3, $t3, 0 #clear $t3
addi $t3, $t3, 4 #assign 4 to $t3
add $s1, $s1, $t3 #second member of stack
lw $t1, 0($s1) #d2
addi $t3, $t3, -4 #move $t3 forward
add $s1, $s1, $t3 #first member of stack
lw $t0, 0($s1) #d1
add $t0, $t0, $t1 #d1 = d1 +d2
sw $t0, 0($s1) #store new d1 at d1's location
I'm trying to create a mips program, which gets last-1 and last member of the stack, and add them, and store it. I don't care about addi $t3, $t3, 4 or stack: .word 3, 2 it's just for test.
However, when I run this at qtspim I got an error message "attempt to execute non-instruction at 0x0040004c" please enlighten me as to what the problem is.
You need to end your program with a jr $ra, otherwise the processor will just keep executing whatever random instructions that happen to come after the sw $t0, 0($s1).

MIPS, Recursion

I trying to write a MIPS program that gets an unsigned integer as argument and returns the sum of all decimal digits in the integer recursively. For example if the argument is 75080 then the sum to be returned is 20 (7+5+0+8+0). Here is my code so far. Any help would be appreciated.
My way of thinking was to divide the number by 10 leaving me with the last integer in the number, add the reminder using mfhi.
.data
prompt: .asciiz "Enter a string of integer: "
output: .asciiz "\nThe total sum is: "
.text
.globl main
main:
la $a0, prompt
li $v0, 4
syscall
li $v0, 5
syscall
move $t2, $v0
la $a0, output
li $v0, 4
syscall
Loop:
div $t2, $t2, 10
mflo, $t1
mfhi, $t3
beqz $t1, Exit
add $t1, $t1, 0
b additive
additive:
add $t0, $t1, $t1
j Loop
Exit:
la $a0, output
li $v0, 4
syscall
la $v0, 10
syscall
What's this supposed to be doing? Adding 0 to the register won't change its value:
add $t1, $t1, 0
After dividing and copying to $t1 and $t3, the quotient is in $t1 and the remainder is in $t3. You're treating it the other way around when you add to the total.
This is actually going to give you $t0 = 2 * $t1: you're adding $t1 to itself and storing the result in $t0.
add $t0, $t1, $t1
You probably actually want:
add $t0, $t0, $t3
You're checking for $t1 == 0 before adding the remainder to the total, so the most significant digit will never get added. You don't really need a subroutine for adding to the total either. You can also use bnez Loop instead of beqz Exit -> b Loop. Lastly, you don't even need $t1, because the quotient is already in $t2.
Get rid of additive and replace Loop with this:
Loop:
div $t2, $t2, 10
mfhi, $t3
add $t0, $t0, $t3
bnez $t2, Loop
Your Exit is weird: you're printing the output string a second time instead of printing the integer.
Change it to this:
Exit:
move $a0, $t0
la $v0, 1
syscall
la $v0, 10
syscall
The approach is quite simple. You need recursive function, I named it SumDigits that will take the last digit and repeat procedure for all digits in the argument. After the recursive call returns you'll add digit to the previous result. The code is commented for easier understanding. The code follows:
.text
#calculates sum of digits recursively
SumDigits:
sub $sp, $sp, 12 #alloocate 12B on stack
sw $ra 0($sp) #save return address
sw $a0, 4($sp) #save argument
beq $a0, $0, exit_sumdigits #when there is no more digits return 0
rem $t0, $a0, 10 #get last digit
sw $t0, 8($sp) #save it on stack
div $a0, $a0, 10 #divide argument by 10
jal SumDigits #repeat procedure
lw $t0, 8($sp) #read digit from stack
add $v0, $v0, $t0 #add digit to previous result
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
exit_sumdigits:
li $v0, 0 #there are no more digits, return 0
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
main:
li $a0, 75080 #load number in $a0
jal SumDigits #call SumDigits
move $a0, $v0 #set a0 = result of SumDigits
li $v0, 1 #set $v0 for print int system call
syscall
li $v0, 10 #set $v0 for exit system call
syscall
.data

Unsetting and resetting certain bits

For a homework assignment in school, I need to use a MMIO LED display where each led is exactly 2 bits stored within a byte. For the assignment I need to "move" these LEDs up, down, left, and right. I also need to set the color (I will be using 0x40 for this). Here's my issue:
When I click the "right" arrow to move the LED over 1 column, it remains in the current column when it should be returning to black (0x00). If I click right 4 times (moving over exactly 1 byte), I get another lit LED, leaving the original one there.
Here is my MIPS code:
getLedPattern:
move $t2, $s2
andi $t1, $t2, 0x3 #remainder of x / 4 is in $t0
sll $t0, $t2, 2 #x / 4 is in $t0
beq $t0, 0, case0
beq $t0, 1, case1
beq $t0, 2, case2
case3:
andi $a0, 0xFFFFFFFC
#insert $a1 into bits 0 and 1 of $a0 into $v0
or $v0, $a0, $a1
jr $ra
case2:
andi $a0, 0xFFFFFCFF
#insert $a1 into bits 2 and 3 of $a0 into $v0
#srl $a1, $a1, 2
or $v0, $a0, $a1
jr $ra
case1:
andi $a0, 0xFFFCFFFF
#insert $a1 into bits 4 and 5 of $a0 into $v0
#srl $a1, $a1, 4
or $v0, $a0, $a1
jr $ra
case0:
andi $a0, 0xFCFFFFFF
#insert $a1 into bits 6 and 7 of $a0 into $v0
#srl $a1, $a1, 6
or $v0, $a0, $a1
jr $ra
setLED:
addi $sp, $sp, -20
sw $ra, 0($sp)
sw $t0, 4($sp)
sw $t1, 8($sp)
sw $t2, 12($sp)
sw $t3, 16($sp)
move $t5, $a0
sll $t6, $a1, 5 # y*32
srl $t2, $a2, 2 # x/4
add $t5, $t5, $t6
add $t5, $t5, $t2
lb $a0, 0($t5)
move $a1, $a3
jal getLedPattern
sb $v0, 0($t5)
move $s3, $t5
lw $ra, 0($sp)
lw $t0, 4($sp)
lw $t1, 8($sp)
lw $t2, 12($sp)
lw $t3, 16($sp)
addi $sp, $sp, 20
jr $ra
The logic is that it starts out at at memory location 0xFFFFOOO8 (top left LED), moves down one row (+32 bytes) and over x columns (plus x*bits). However, I can't seem to unset the current LED and move it over one. Any help would be appreciated. I believe that my or in getLedPattern: is wrong, but not 100% sure.
Hopefully, getting this correct I will be able to get this correct in a general sense (no LED display).
I guess that your constants for clearing bits are wrong.
try the following instead:
0xfffffffc // or ~0x03
0xfffffff3 // or ~0x0C
0xffffffcf // or ~0x30
0xffffff3f // or ~0xC0
There are other oddity in your code:
s2 is used, but never set
s3 is set, but never used
case1 and case2 will never be reached because $t0 can hold nor 1 neither 2