Related
I am working on a program that calculates combinations in MIPS. The user enters the size of the pool, and number of balls to pick from it, and the program should output the total combinations. The program correctly calculates the numerator, but when it comes to dividing the numerator (n!) by the denominator, which is also correctly calculated, the combinations number is wrong.
I think something goes wrong with $t2 when it is used in main, but not sure what exactly or how to fix it.
.data
message1: .asciiz "Enter input for the size of the large pool: "
message2: .asciiz "Enter input for # of balls to be selected from large pool: "
message5: .asciiz "The numerator is: "
newline: .asciiz "\n"
.text
.globl main
main:
# Call on function messages
jal messages
# Calculate factrl for # from large pool size
move $a0, $s2
jal factrl # Call on factrl function
move $t5, $v0
# Find (n-k) for large pool
sub $t0, $s1, $s2
# Intialize $t2 to 1
li $t2, 1
# Call function while for large pool
move $a1, $s1
move $a2, $t0
jal while
move $v0, $t2
# Find probability for large
move $a0, $v0
move $a1, $t0
jal combination
move $t7 $v0
li $v0, 4
la $a0, newline
syscall
li $v0, 1
add $t7, $t7, $zero
syscall
# Exit Program
li $v0, 10
syscall
messages:
# Request size of large pool
li $v0, 4
la $a0, message1
syscall
# Get input for size of large pool
li $v0, 5
syscall
# Store input in register
move $s1, $v0
# Request # selected from large pool
li $v0, 4
la $a0, message2
syscall
# Get input for # of large pool
li $v0, 5
syscall
# Store input in register
move $s2, $v0
li $v0, 4
la $a0, newline
syscall
jr $ra
factrl:
sw $ra, 4($sp) # save the return address
sw $a0, 0($sp) # save the current value of n
addi $sp, $sp, -8 # move stack pointer
slti $t0, $a0, 2 # save 1 iteration, n=0 or n =1; n!=1
beq $t0, $zero, L1 # not less than 2 , calculate n(n - 1)!
addi $v0, $zero, 1 # n=1; n!=1
jr $ra # now multiply
L1:
addi $a0, $a0, -1 # n = n - 1
jal factrl # now (n - 1)!
addi $sp, $sp, 8 # reset the stack pointer
lw $a0, 0($sp) # fetch saved (n - 1)
lw $ra, 4($sp) # fetch return address
mul $v0, $a0, $v0 # multiply (n)*(n - 1)
jr $ra # return value n!
while:
addi $sp, $sp, -8 # allocate space in stack
sw $ra, 4($sp)
sw $a1, 0($sp) # store the value of $s1 on the stack
beq $a1, $a2, numerator
mult $t2, $a1 # multiply val x n
mflo $t3
move $t2, $t3
addi $a1, $a1, -1 # n = n-1
j while
numerator:
li $v0, 4
la $a0, message5
syscall
# Print the numerator
li $v0, 1
move $a0, $t2
syscall
lw $a1, 0($sp)
addi $sp, $sp, 8 # reset stack pointer
jr $ra
combination:
div $v0, $a1, $a0
jr $ra
exit:
li $v0, 10
syscall
I am currently trying to figure out why my mars program for creating an array is getting stuck in an infinite loop. I am trying to create an array using different functions and in the create array function the program is supposed to jump into a get number function and return the value to store it into the array but the counter seems to not be decrementing and it just keeps asking for an element for the array. Here is the code:
.data
str5: .asciiz "Please enter a number of elements for the array between 0 and 20: "
str6: .asciiz "Please enter an element: "
array: .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.text
main:
begin:
li $v0, 4
la $a0, str5
syscall
jal readnum
add $a0, $v0, $0
jal verify
add $a0, $v0, $0
jal createarray
la $s1, array
jal printarray
li $v0, 10
syscall
printarray:
createarray:
add $t0, $ra, $0
add $s0, $a0, $0
add $t9, $0, $0
la $s1, array
loop:
beq $s0, 0, done
li $v0, 4
la $a0, str6
syscall
jal readnum
add $t1, $v0, $0
sw $t1, 0($s1)
addi $s1, $s1, 4
addi $s0, $s0, -1
addi $t9, $t9, 1
j loop
done:
add $ra, $t0, $0
jr $ra
verify:
add $s0, $a0, $0
bge $s0, 20, begin
ble $s0, 0, begin
add $v0, $s0, $0
jr $ra
readnum:
li $v0, 5
syscall
jr $ra
EDIT: After re-reading the code, what is causing the error is actually the following code:
jal printarray
You never did the following code in printarray:
jr $ra
So, it would go back down to the other functions.
Use the $sp (the proper way to handle the $ra when calling functions within functions)
The following segment is the cause of the problem:
syscall
jal readnum
add $t1, $v0, $0
Moreso specifically the jal call. Calling a function within a function requires some more steps to be taken place.
First, understand what the jal instruction is doing. The jal instruction, put simply, marks where you currently are and stores it in the $ra register. Then, it will jump to that function.
But there's a problem: you are already wishing for the $ra register to remember where you once were because you, in fact, called createarray!
So, you called createarray, making $ra store where you once were, then within that function you called readnum, making $ra store where you are in createarray. **But now, you have lost where you once were before called createarray. So, it will keep looping back to what $ra used to be, which is inside your createarray function.
Fortunately, the $sp register is just what you need
How to use the $sp register
To store where we are, we push to the stack:
addi $sp, $sp, -4 # by convention, we use negative numbers when pushing
sw $ra, ($sp)
To get where we once were after we called the function (which replaced our $ra in the first place), we pop the stack:
lw $ra, ($sp)
addi $sp, $sp, 4 # by convention, we use positive numbers when popping
So in the grand scope of things, here is what you do:
# push to the stack
addi $sp, $sp, -4
sw $ra, ($sp)
jal theFunctionWeWantToCallInOurFunction
# pop the stack, get back our $ra
lw $ra, ($sp)
addi $sp, $sp, 4
Let's apply this solution to your codebase:
.data
str5: .asciiz "Please enter a number of elements for the array between 0 and 20: "
str6: .asciiz "Please enter an element: "
array: .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.text
main:
begin:
li $v0, 4
la $a0, str5
syscall
jal readnum
add $a0, $v0, $0
jal verify
add $a0, $v0, $0
jal createarray
la $s1, array
jal printarray # comment off this line and you won't have an infinite loop
li $v0, 10
syscall
printarray:
createarray:
add $t0, $ra, $0
add $s0, $a0, $0
add $t9, $0, $0
la $s1, array
loop:
beq $s0, 0, done
li $v0, 4
la $a0, str6
syscall
# store where we wish to come back to so that $ra can be overriden without losing data.
addi $sp, $sp, -4
sw $ra, ($sp)
# call the function. jal will replace our current $ra
jal readnum
# retrieve what our $ra once was
lw $ra, ($sp)
addi $sp, $sp, 4
add $t1, $v0, $0
sw $t1, 0($s1)
addi $s1, $s1, 4
addi $s0, $s0, -1
addi $t9, $t9, 1
j loop
done:
add $ra, $t0, $0
jr $ra
verify:
add $s0, $a0, $0
bge $s0, 20, begin
ble $s0, 0, begin
add $v0, $s0, $0
jr $ra
readnum:
li $v0, 5
syscall
jr $ra
I am attempting to recreate a C-snippet in assembly. The C program essentially:
creates a char array[256] along with a pointer *A initialized to NULL.
User input of some string is then stored into the char array
while each ith element of the array != 0
check it the ith element is == some DEFINED char value V.
If array[i] == V -> set A = &array[i]
break
Lastly check if A is still initialized to NULL
if not pint address and value of A
else not found
Unfortunately, when I run the MIPS code with Qtspim I get the aforementioned error Exception occurred at PC=0x004000a8
-> (Abort after)
-> Followed by Unaligned address in inst/data fetch: 0x1001012b
I feel like it has something to do with the way that I store my byte values in the array or the way I am accessing those memory locations but I can't figure out what the problem is. Any insight that anyone can offer would be greatly appreciated. Happy holidays everyone!
Bellow is my assembly code:
# global functions aforementioned error
.globl main
# .text assembler directive
.text
# main
main:
# register map
# use $t0 for i
# use $t1 for NULL
# use $s0 for &inputArray[i]
# use $s1 for indexed array value
# use $s2 for the base address inputArray
# use $s3 for result
# use $t2 for constCharlwr
# Prompt user for input
la $a0, str1
li $v0, 4
syscall
# Get user input and store in input array
la $a0, inputArray
li $a1, 256
li $v0, 8
syscall
# set up registers
lb $t0, i
lb $t1, NULL
la $s2, inputArray
lb $s3, result
lb $t2, constCharlwr
li $s0, 0
add $s0, $s0, $s2 # s0 = &arrayA[i]
while: # while loop
add $s0, $s0, $t0 # base address + 1 byte
lb $s1, 0($s0) # load array index value into s1
beq $s1, $t1, outsideWhile # inputArray[i] != '\0'
if1:
bne $s1, $t2, outsideIf # check if inputArray[i] == e
move $s3, $s1 # if true copy s1(inputArray[i] into s3(result)
sb $s3, result
j outsideWhile
outsideIf:
addi $t0, $t0, 1
j while
outsideWhile:
if2:
beq $s3, $t1, else
# Print results
# Print string 2
lw $a0, str2
li $v0, 4
syscall
# Print address of result
la $a0, result
li $v0, 4
syscall
# Print next line
lb $a0, nextline
li $v0, 4
syscall
# Print string 3
lw $a0, str3
li $v0, 4
syscall
# Print result char value
lb $a0, result
li $v0, 4
syscall
# Print next line
lb $a0, nextline
li $v0, 4
syscall
j exitPrgm
else:
# Print No match
lw $a0, str4
li $v0, 4
syscall
# Exit the program by means of syscall.
exitPrgm:
li $v0, 10 # Sets $v0 to "10" to select exit syscall
syscall # Exit
# .data assembler directive
.data
inputArray: .space 256
constCharlwr: .byte 'e'
result: .byte 0
NULL: .byte 0
i: .byte 0
str1: .asciiz "Enter a word to search for letter e: \n"
str2: .asciiz "First match at address "
str3: .asciiz "The matching character is "
str4: .asciiz "No match found\n"
nextline: .asciiz "\n"
Ok, so I figured out my initial problem, I was not using la for my sys calls and once I fixed that I started getting the output that I wanted. The only problem now is I can figure out how to print the actual address of the result. Can someone help me with this.
New Code, Trying a few diffrent things to get the memory address but nothing seems to work.
# Prompt user for input
la $a0, str1
li $v0, 4
syscall
# Get user input and store in input array
la $a0, inputArray
li $a1, 255
li $v0, 8
syscall
# set up registers
lb $t0, i
lb $t1, NULL
la $s2, inputArray
lb $s3, result
lb $t2, constCharlwr
li $s0, 0
add $s0, $s0, $s2 # s0 = &arrayA[i]
while: # while loop
add $s0, $s0, $t0 # base address + 1 byte
lb $s1, 0($s0) # load array index value into s1
beq $s1, $t1, outsideWhile # inputArray[i] != '\0'
if1:
bne $s1, $t2, outsideIf # check if inputArray[i] == e
sb $s1, result
j outsideWhile
outsideIf:
addi $t0, $t0, 1
j while
outsideWhile:
if2:
beq $s1, $t1, else
# Print results
# Print string 2
la $a0, str2
li $v0, 4
syscall
# Print address of result
la $t9, result
li $t8, 4
li $t0, 0
#for:
# bge $t0, $t8 outsideFor
# add $t9, $t9, $t0
# lb $t7, 0($t9)
# sb $t7, resultAddr
# la $a0, resultAddr
# li $v0, 4
# syscall
# addi $t0, $t0, 1
# j for
#outsideFor:
sb 0($t9) resultAddr
la $a0, resultAddr
li $v0, 4
syscall
sb 1($t9) resultAddr
la $a0, resultAddr
li $v0, 4
syscall
sb 2($t9) resultAddr
la $a0, resultAddr
li $v0, 4
syscall
sb 3($t9) resultAddr
la $a0, resultAddr
li $v0, 4
syscall
# Print next line
la $a0, nextline
li $v0, 4
syscall
# Print string 3
la $a0, str3
li $v0, 4
syscall
# Print result char value
la $a0, result
li $v0, 4
syscall
# Print next line
la $a0, nextline
li $v0, 4
syscall
j exitPrgm
else:
# Print No match
la $a0, str4
li $v0, 4
syscall
So ive been able to create an array that is the size of what the user chooses and the code proceeds to Sort just fine when debugging, the issue is for some reason its not getting past Sort and into swap and im not quite sure why. In the debugger it seems to read the code to swap but then skips over it and repeats sort in an infinite loop. Am i doing something wrong?
.data
count: .word 0
prompt1: .asciiz "Enter the array size \n"
prompt2: .asciiz "Enter integers to fill the array \n"
prompt3: .asciiz "Sorted Array: "
.text
li $v0, 4
la $a0, prompt1
syscall
li $v0, 5
syscall
sw $v0, count
sll $a0, $v0, 2
li $v0, 9
syscall
move $t0, $v0
lw $t1, count
loop:
li $v0, 4
la $a0, prompt2
syscall
li $v0, 5
syscall
beqz $v0, sort
sw $v0, 0($t0)
addi $t0, $t0, 4
sub $t1, $t1, 1
bnez $t1, loop
sort:
lw $t3, 0($t0)
lw $t4, 4($t0)
blt $t4, $t3, swap
addiu $t0, $t0, 4
addi $t1, $t1, -1
bne $t1, $zero, sort
jr $ra
swap:
sw $t3, 4($t0)
sw $t4, 0($t0)
j sort
end:
exit:
li $v0, 10
syscall
I am making a program for a user to input a range of numbers, and calculate the min, max and median. Right now, I am only trying to collect the numbers and echo them back to make sure I am getting them. Here is the problem:
I input numbers like this:
1
2
3
4
5
And when the array is printed out I get:
15345
It does not matter what numbers are used, the 2nd element in the array is always replace by the last element.
Here is my mips code, I know it is kind of long, but it is the shortest workable example I can make.
Note: you must enter 9999 for the program to exit the loop.
.data
welcomeString: .asciiz "Please input one number at a time, and then press enter.\n"
intArray: .word 4000
size: .word 0
.text
main:
li $v0, 4
la $a0, welcomeString
syscall
la $a0, intArray
jal gather_numbers
la $a0, intArray
jal print_array
####################################################################################
gather_numbers:
addi $sp, $sp, -12
sw $a0, 0($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $t1, 12($sp)
move $s0, $a0 #the address of the array
lw $s1, size # load the size
li $t1, 0 # so it enters the loop
start_gather_numbers: beq $t1, 9999, exit_gather_numbers
li $v0, 5 # read the integer
syscall
sw $v0, 0($s0)
move $t1, $v0 # put the value into t1 to be tested
addi $s0, $s0, 4 #increment the address
addi $s1, $s1, 1 # increment the size
j start_gather_numbers
exit_gather_numbers: addi $s1, $s1, -1 # fix the size
sw $s1, size # store the size
lw $a0, 0($sp) # pop the stack
lw $s0, 4($sp)
lw $s1, 8($sp)
lw $t1, 12($sp)
addi $sp, $sp, 12
####################################################################################
####################################################################################
print_array:
addi $sp, $sp, -16
sw $a0, 0($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $t0, 12($sp)
sw $t1, 16($sp)
move $s0, $a0 # the address of the array
lw $s1, size # load the size of the array
li $t0, 0 # i = 0
start_print_array: bge $t0, $s1, exit_print_array
lw $t1, 0($s0) # load the int to print
li $v0, 1 # print the integer
move $a0, $t1
syscall
addi $s0, $s0, 4
addi $t0, $t0, 1
j start_print_array
exit_print_array: lw $a0, 0($sp)
lw $s0, 4($sp)
lw $s1, 8($sp)
lw $t0, 12($sp)
lw $t1, 16($sp)
addi $sp, $sp, 16
There are a few things going wrong here.
Firstly all of your functions are missing the terminating jr $ra.
Also, your stack manipulation is wrong. You are consistently allocating 4 less bytes than you use. If you want to put 5 words on the stack you should expand the stack by 20 not 16.
Most importantly though here is your intArray directive. You have used .word 4000 I'm guessing to allocate an array of ints, but rather you have allocated space for 1 word with the value 4000.
To instead allocate an array of 1000 ints you could use .space 4000 or equally .word 0:1000.
When I made these changes your program began to function as desired.