creating a check for a loop in driver - mips

I created code for a procedure that outputs the factoral of a number given. But it needs to ask the user for a number until they enter a negative before it exits.
So that it looks something like this
Enter a value for n (or a negative value to exit): 6
6! is 720
Enter a value for n (or a negative value to exit): 9
9! is 362880
Enter a value for n (or a negative value to exit): 11
11! is 39916800
Enter a value for n (or a negative value to exit): 20
20! is -2102132736
Enter a value for n (or a negative value to exit): 100
100! is 0
Enter a value for n (or a negative value to exit): -1
Thanks for Testing!
Instead of something like this.
Enter the value of a number (or negative to exit): 5
Value returned is 120
Thanks for testing!
fact:
slti $t0, $a0, 1 # test for n < 1
beq $t0, $zero, L1 # if n >= 1, go to L1
li $v0, 1 # return 1
jr $ra # return to instruction after jal
L1:
addi $sp, $sp, -8 # adjust stack for 2 items
sw $ra, 4($sp) # save the return address
sw $a0, 0($sp) # save the argument n
addi $a0, $a0, -1 # n >= 1; argument gets (n – 1)
jal fact # call fact with (n – 1)
lw $a0, 0($sp) # return from jal: restore argument n
lw $ra, 4($sp) # restore the return address
addi $sp, $sp, 8 # adjust stack pointer to pop 2 items
mul $v0, $a0, $v0 # return n * fact (n – 1)
jr $ra # return to the caller
main:
la $a0, nreq # get value of n
li $v0, 4
syscall
li $v0, 5 # read value of n
syscall
move $a0, $v0 # place value n in $a0
jal fact # invoke fact
move $s0, $v0 #save value returned by facts
la $a0, ans # display
li $v0, 4
syscall
move $a0, $s0
li $v0, 1
syscall
la $a0, cr #display closing
li $v0, 4
syscall
li $v0, 10 # exit
syscall
.data
nreq: .asciiz "Enter a value for n (or negative to exit): "
ans: .asciiz "Value returned is "
cr: .asciiz "\nThanks for testing!\n"

Overall, pretty close. However, one or two things.
I'd move main to the top, above fact, as some simulators start at the lowest .text address rather than the given symbol main. For example, in mars, this didn't seem to work until I reversed the order.
main was missing the test for negative input and didn't loop on itself.
Here's a version that seems to work [please pardon the gratuitous style cleanup]:
.text
.globl main
main:
la $a0,nreq # get value of n
li $v0,4
syscall
li $v0,5 # read value of n
syscall
# NOTE/BUG: add this
bltz $v0,exit # exit program on negative
move $a0,$v0 # place value n in $a0
jal fact # invoke fact
move $s0,$v0 # save value returned by facts
la $a0,ans # display
li $v0,4
syscall
move $a0,$s0
li $v0,1
syscall
# NOTE: add this
li $v0,4
la $a0,nl
syscall
j main
exit:
la $a0,cr # display closing
li $v0,4
syscall
li $v0,10 # exit
syscall
fact:
slti $t0,$a0,1 # test for n < 1
beq $t0,$zero,L1 # if n >= 1, go to L1
li $v0,1 # return 1
jr $ra # return to instruction after jal
L1:
addi $sp,$sp,-8 # adjust stack for 2 items
sw $ra,4($sp) # save the return address
sw $a0,0($sp) # save the argument n
addi $a0,$a0,-1 # n >= 1; argument gets (n – 1)
jal fact # call fact with (n – 1)
lw $a0,0($sp) # return from jal: restore argument n
lw $ra,4($sp) # restore the return address
addi $sp,$sp,8 # adjust stack pointer to pop 2 items
mul $v0,$a0,$v0 # return n * fact (n – 1)
jr $ra # return to the caller
.data
nreq: .asciiz "Enter a value for n (or negative to exit): "
ans: .asciiz "Value returned is "
nl: .asciiz "\n"
cr: .asciiz "\nThanks for testing!\n"

Related

MIPS program for calculating n choose k using recursion

I started a course of assembly and I am using MIPS as the programming language. I try to solve the problem of n choose k. Here is the code that I got so far but it always shows 1 as the result.
# Calculate n choose k
#
# n: integer value for n
# k: integer value for k
#
# Return: integer value for n choose k
.text
.globl nChooseK
nChooseK:
# Check if k is equal to 0 or k is equal to n
beq $a1, $zero, return_1
beq $a1, $a0, return_1
# Calculate n-1 choose k-1
sub $t0, $a0, 1
sub $t1, $a1, 1
jal nChooseK
move $t2, $v0
# Calculate n-1 choose k
move $a0, $a0
move $a1, $t1
jal nChooseK
move $t3, $v0
# Return the sum of the two calculations
add $v0, $t2, $t3
jr $ra
return_1:
# Return 1 if k is equal to 0 or k is equal to n
li $v0, 1
# Print the result of n choose k
.globl main
main:
li $a0, 5 # Load the value of n into $a0
li $a1, 3 # Load the value of k into $a1
#jal nChooseK # Call the nChooseK function
move $a0, $v0 # Load the result into $a0
li $v0, 1 # Set $v0 to 1 to print an integer
syscall # Print the result
li $v0, 10 # Set $v0 to 10 to exit the program
syscall # Exit the program
Your problem is most likely here:
return_1:
# Return 1 if k is equal to 0 or k is equal to n
li $v0, 1
# fallthrough into main (comment added by me). Put jr $ra here
# Print the result of n choose k
.globl main
Regardless of your input, eventually one of your recursions will have to return 1 as a base case. So, what's happening is, you're setting $v0 to 1 and going back into main. Now, that being said, I'm not sure why this doesn't result in an infinite loop, since you'd end up calling nChooseK over and over again and overflow the stack. Could be that you've commented out the jal nChooseK down at the bottom.

MIPS getting an error when running my code

For our coursework we had to write code in MARS to calculate the memory address of a given coordinate.
.globl main
.data
amountOfRows: .word 16 # The mount of rows of pixels
amountOfColumns: .word 32 # The mount of columns of pixels
promptRows: .asciiz "Please enter the row number:\n"
promptCols: .asciiz "Please enter the column number:\n"
msgShowMemoryAddress: .asciiz "The memory address for the pixel is:\n"
msgErrorValues: .asciiz "The entered value for row/column is invalid, please enter a valid value:\n"
.text
###################################################################################
translate_coordinates:
sw $fp, 0($sp) # push old frame pointer (dynamic link)
move $fp, $sp # frame pointer now points to the top of the stack
subu $sp, $sp, 20 # allocate 16 bytes on the stack
sw $ra, -4($fp) # store the value of the return address
sw $s0, -8($fp) # save locally used registers
sw $s1, -12($fp)
sw $s2, -16($fp)
move $s0, $a0 # $s0 = x coordinate
move $s1, $a1 # $s1 = y coordinate
move $s2, $a2 # $s2 = width for calculations
sll $t3, $s1, 5 # shift y left by 5 which is equal to multiplication of 32
add $t4, $t3, $s0 # (y * 32) + x = index of pixel
sll $t5, $t4, 2 # shift index left by 2 which is equal to multiplication of 4
add $t6, $gp, $t5 # memory address = gp + offset
move $v0, $t6 # place result in return value location
lw $s2, -16($fp) # reset saved register $s2
lw $s1, -12($fp) # reset saved register $s1
lw $s0, -8($fp) # reset saved register $s0
lw $ra, -4($fp) # get return address from frame
move $sp, $fp # get old frame pointer from current fra
lw $fp, ($sp) # restore old frame pointer
jr $ra
###################################################################################
main:
li $v0, 4 # print string
la $a0, promptRows # message to ask the user for the row number
syscall
li $v0, 5 # read integer
syscall # ask the user for a row number
move $t0, $v0
li $v0, 4 # print string
la $a0, promptCols # message to ask the user for the column number
syscall
li $v0, 5 # read integer
syscall # ask the user for a column number
move $t1, $v0
lw $t2, amountOfColumns #load amountOfColumns into $t2
move $a0, $t0 # Put procedure arguments
move $a1, $t1 # Put procedure arguments
move $a2, $t2
jal translate_coordinates # Call procedure
move $t6, $v0 # Get procedure result
move $a0, $t6
li $v0, 1 # syscall code 1 is for print_int
syscall
exit:
li $v0, 10 # syscall to end the program
syscall
I wrote this code to calculate the memory address of a pixel but whenever I run it I get this error:
Error in : invalid program counter value: 0x00000000
We had to use a stackframe for this and I'm quite new to that.
Because I'm quite new to it, it might be that I made some mistakes when it comes to that.
By default, MARS starts running the code at the start of .text, and since in your code the function comes before main, it is running the function without calling it properly.
There are three options:
add j main immediately after .text
use MARS option Settings -> Initialize Program Counter to global main if defined (off by default)
change the order so that main comes immediately after .text

How to count the number of words and print the result in mips?

So I am fairly new to mips and am trying to do a hmwk.
The exercise is to create a block of words with 0 as the last word , to count them knowing we don't consider the last element 0 and print out the result.
Here is my code for the moment
.data
blockOfWords: .word 12,43,549,7,60,0
.text
la $a0, blockOfWords #putting address of blockOfWords in $a0
loopStart: sll $t1, $s3,2 #iterates thru blockOfWords by jumping by 4 bytes, $t1=4*i
add $t1,$t1,$a0 #we increment the address by four so as to advance in the array after every iteration
lw $a1, 0($t1) #$a1=blockOfWOrds[i]
beq $a1,$zero, Exit #if the value in $a1[i]==0, exit the loop
addi $s0,$s0,1 #else, increment by one the cnt=$s0
j loopStart #and continue looping thru blockOfWords
Exit:
#how do i print the result?
So instead of doing a shift left logical it is a lot easier to up the memory address in the array
In this way the lw $a1, 0($a0) is just grabbing the beginning of the word
it is then incremented by 4 after a check for the 0. This makes the function much simpler and easier to read.
.data
blockOfWords: .word 12,43,549,7,60,0
.text
main:
la $a0, blockOfWords # Load beginning address into $a0
loopStart:
lw $a1, 0($a0) # load the value at the beginning of $a0 into $a1
beq $a1,$zero, exit # Check if $a1 is 0, if so jump to exit
addi $s0,$s0,1 # Add one to the count
addi $a0, $a0, 4 # Up the intial index of the array by 4, up one word
j loopStart # Re-loop
exit:
li $v0, 1 # Load the value of 1 into the $v0 register
la $a0, ($s0) # Load the counter into the $a0 address
syscall
li $v0, 10 # A value 10 syscall to indicate end of program
syscall

Why am i getting Runtime exception: fetch address not aligned on word boundary

I had task for my schoolwork that included this code and i need to fix it but i can't continue now... The code is supposed to move one array t
.data
source: .word 3, 1, 4, 1, 5, 9, 0
dest: .word 0, 0, 0, 0, 0, 0, 0
countmsg: .asciiz " values copied. "
.text
main: la $a0,source
la $a1,dest
loop: lw $v1, 0($a0) # read next word from source
addiu $v0, $v0, 1 # increment count words copied
sw $v1, 0($a1) # write to destination
addiu $a0, $a0, 1 # advance pointer to next source
addiu $a1, $a1, 1 # advance pointer to next dest
bne $v1, $zero, loop# loop if word copied not zero
loopend:
move $a0,$v0 # $a0 <- count
jal puti # print it
la $a0,countmsg # $a0 <- countmsg
jal puts # print it
li $a0,0x0A # $a0 <- '\n'
jal putc # print it
finish:
li $v0, 10 # Exit the program
syscall
### The following functions do syscalls in order to print data (integer, string, character)
#Note: argument $a0 to syscall has already been set by the CALLEE
puti:
li $v0, 1 # specify Print Integer service
syscall # Print it
jr $ra # Return
puts:
li $v0, 4 # specify Print String service
syscall # Print it
jr $ra # Return
putc:
li $v0, 11 # specify Print Character service
syscall # Print it
jr $ra # Return
It returns Runtime exception at 0x00400010: fetch address not aligned on word boundary 0x10010001
The error is on line 11 i think but i can't solve it.
Shouldn't it be addiu $a0, $a0, 4 as you have to jump to next word
You are advancing pointers wrong.
If the elements of your array are words, then you have to use lw/sw to read/write elements from/to the array and take into account that each element occupies 4 bytes (thus, 1 word). So to advance the pointer you have to add 4 to the pointer ($a0 and $a1 in your code).
If you were trying to use an array of bytes then you'd use .byte directive to define your array, lb/sb and advance the pointer by increment it 1 position at a time (as you are doing in your code).

MIPS Output Error

I have an unknown output error after entering 2nd value which is after entering base number.
Hopefully,some of you could identify my error:
ERROR:Instruction references undefined symbol at 0x00400060
[0x00400060] 0x102a0000 beq $1, $10, 0 [hex-0x0040005c]
PROGRESS:Currently stucked at Step 2.
What i want to do is,
1)User enter a decimal value
2)User enter type of conversion
3)Go to desired subroutine depending on type of conversion chosen earlier
4)Display output
.data
prompt: .asciiz "Enter the decimal number to convert: "
base: .asciiz "Select type of base (2 for binary,16 for hexadecimal or 8 for octal): "
ans1: .asciiz "\nBinary Output is equivalent:"
ans2: .asciiz "\nOctal Output is equivalent:"
ans3: .asciiz "\nHexadecimal Output equivalent:0x"
result1: .space 8
.text
.globl main
main:
la $a0, prompt #Display message
li $v0, 4
syscall
li $v0, 5
syscall
beq $v0, $zero, Exit #Exit if 0 decimal is entered
move $t0, $v0 #Else copy value entered into temporaries
askbase:
li $v0, 4
la $a0, base #Display message
syscall
li $v0, 5
syscall
add $t1,$zero,$v0 #Add desired value/base entered into t1
beq $t2,16,hex #if base 16 is entered,goto hex subroutine
beq $t2,8,oct
beq $t2,2,bin
la $a0, ans3
li $v0, 4
syscall
li $t0, 8 # counter
la $t3, result1 # where answer will be stored
Hex:
beqz $t0, Exit # branch to exit if counter is equal to zero
rol $t2, $t2, 4 # rotate 4 bits to the left
and $t4, $t2, 0xf # mask with 1111
ble $t4, 9, Sum # if less than or equal to nine, branch to sum
addi $t4, $t4, 55 # if greater than nine, add 55
b End
Sum:
addi $t4, $t4, 48 # add 48 to result
End:
sb $t4, 0($t3) # store hex digit into result
addi $t3, $t3, 1 # increment address counter
addi $t0, $t0, -1 # decrement loop counter
j Loop
Exit: la $a0, result1
li $v0, 4
syscall
la $v0, 10
syscall
It looks like you have a typo at line 29 beq $t2,16,hex should be beq $t2,16,Hex. Note the capital letter on Hex. You also have a number of undefined labels: Loop, oct, bin... Without those labels you are going to have issues. It is a good idea to just set some up as place holders (until you have their subroutines defined). Maybe have them all branch to Exit:. The assembler cannot resolve your branch instructions without having the actual labels to go to.
You haven't stored anything in $t7, so there's no particular reason to expect that $t7 would equal 16.
What you probably wanted to write is:
beq $t1,16,hex
Since $t1 is the register that you stored the base in.
However, I really don't see why you would want that jump with the way the code currently is structured. The hex subroutine relies on a few registers (like $t0 and $t3) to have been initialized to certain values, and that initialization would be skipped if that beq is taken.