Detect Add overflow - overflow

What would be a good loop to check when overflow occurs in the mips code I have bellow? It is a program i've came up with to balance a checkbook by basically adding deposits to the account. I just keep getting incorrect values when overflow occurs. I need a loop that detects that overflow would occur if the value is accepted and then asks for another value without accepting the bad value.
# Functional Description:
# This program can be used to balance your check book.
# <DESCRIBE OVERFLOW FEATURE HERE>
#####################################################################
# Pseudocode:
# Print Header;
# s0 = 0;
# loop: Prompt user for transaction;
# v0 << transaction amount;
# if (v0 = 0) done;
# s0 = s0 + v0;
# PSEUDOCODE FOR OVERFLOW DETECTION ALGORITHM HERE>
# cout << s0
# go to loop
# done:
# cout << "Adios Amigo"
#
######################################################################
# Register Usage:
# $v0: Transaction Amount
# $s0: Current Bank Balance
# <HERE YOU DECLARE ANY ADDITIONAL REGISTERS USED>
######################################################################
.data # Data declaration section
Head: .ascii "\n\tThis program, written by <YOUR NAME>,"
.ascii " can be used to balance your check book."
.asciiz "\n\n\t\t\t\t\t\t\t\t\t Balance"
tabs: .asciiz "\t\t\t\t\t\t\t\t\t"
tran: .asciiz "\nTransaction:"
bye: .asciiz "\n **** Adios Amigo **** "
.text # Executable code follows
main:
li $v0, 4 # system call code for print_string
la $a0, Head # load address of Header message into $a0
syscall # print the Header
move $s0, $zero # Set Bank Balance to zero
loop:
li $v0, 4 # system call code for print_string
la $a0, tran # load address of prompt into $a0
syscall # print the prompt message
li $v0, 5 # system call code for read_integer
syscall # reads the amount of Transaction into $v0
beqz $v0, done # If $v0 equals zero, branch to done
addu $s0, $s0, $v0 # add transaction amount to the Balance
li $v0, 4 # system call code for print_string
la $a0, tabs # load address of tabs into $a0
syscall # used to space over to the Balance column
li $v0, 1 # system call code for print_integer
move $a0, $s0 # move Bank Balance value to $a0
syscall # print Bank Balance
b loop # branch to loop
done: li $v0, 4 # system call code for print_string
la $a0, bye # load address of msg. into $a0
syscall # print the string
li $v0, 10 # terminate program run and
syscall # return control to system
# END OF PROGRAM

If you add two positive numbers together and the result is less than zero, i.e. bit 31 of the result is set, an overflow occurred. If you add two negative numbers together and the result is greater than zero, an overflow occurred. If you add a positive and a negative number, an overflow cannot occur.

Related

I have added a mips code but when I try to plug in 100 it says grade is incorrect but i need to say incorrect when if(grade>100 ||grade<0)

I have added a mips code but when I try to plug in 100 it says grade is incorrect but i need to say incorrect when if(grade>100 ||grade<0)
please let me know how can I do my if else-statement.
the question is if(grade>100 || grade<0) output should be grade is incorrect
.data
enter: .asciiz "Enter an integer : "
name: .asciiz "\n Number is incorrect. Try Again:"
gradeA: .asciiz "\n Grade is A"
gradeB: .asciiz "\n Grade is B"
gradeC: .asciiz "\n Grade is C"
gradeD: .asciiz "\n Grade is D"
gradeF: .asciiz "\n Grade is F"
.text
.globl main
main:
li $v0, 4
la $a0, enter
syscall
li $v0, 5
syscall
add $s0, $v0, $0
li $t1,100
blt $s0,$t1,l1
bgt $s1,0,l1
j exit
l1:
la, $a0,name
blt $s0,90,l2
la $a0,gradeA
j exit
l2:
blt $s0,80,l3
la $a0,gradeB
j exit
l3:
blt $s0,70,l4
la $a0,gradeC
j exit
l4:
blt $s0,60,l5
la $a0,gradeD
j exit
l5:
la,$a0,gradeF
exit:
li $v0, 4
syscall
li $v0, 10
syscall
The code for loop L1 is having a line to print the non accepting cases, you can simply tackle it in a separate loop. blt check if input is less than 100 and the other loops follows as they were before. The other bgt loop which is mentioned in the code below check if the input is greater to hundred and diverts it to the rejecting loop L6.
.data
enter: .asciiz "Enter an integer : "
name: .asciiz "\n Number is incorrect. Try Again:"
gradeA: .asciiz "\n Grade is A"
gradeB: .asciiz "\n Grade is B"
gradeC: .asciiz "\n Grade is C"
gradeD: .asciiz "\n Grade is D"
gradeF: .asciiz "\n Grade is F"
.text
.globl main
main:
li $v0, 4
la $a0, enter
syscall
add $s2, $zero, -1
li $v0, 5
syscall
add $s0, $v0, $0
li $t1,100
blt $s0,$t1,l1
bgt $s0,$t1,l6 ##checks if input is grater than hundread diverts to l6
ble $s0,$s2,l6
bgt $s0,0,l1
j exit
l1:
blt $s0,90,l2
la $a0,gradeA
j exit
l2:
blt $s0,80,l3
la $a0,gradeB
j exit
l3:
blt $s0,70,l4
la $a0,gradeC
j exit
l4:
blt $s0,60,l5
la $a0,gradeD
j exit
l5:
la,$a0,gradeF
j exit
l6:
la,$a0,name ##prints the case is incorrect
j exit
exit:
li $v0, 4
syscall
li $v0, 10
syscall
The code show incorrect number for numbers greater than 100. And for numbers less than zero it assume the grade to be F. If you want the code to indicate incorrect number for negative numbers or float numbers less than zero you can visit :
http://www.cs.jhu.edu/~jorgev/cs333/reference.html
and
https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MIPS_Warrior_M5150_SoftwareUserManual_MD00980_01.05.pdf
For this you have to change the code to float input and use sltu to have an hi or lo register and compare them to get the required error displayed on console.
You can also compare a negative lower limit to the input using ble.

Input Validation MIPS

How do I validate a user input in MIPS instruction set using MARS? In my following program I want to know how I can add validation to user input for example when asking the user if they want to decrypt or encrypt a message they need to input either 'E' or 'D' (case sensitive due to ascii values). As well as an input from (1-9) which is the encryption or decryption key. If they enter anything other than 'E', 'D' and a number from 1-9 how do I ask the user to enter a valid input using a subroutine for each prompt?
Code:
.data
encrypt_decrypt: .asciiz "Type(E)ncrypt/(D)ecrypt:"
key: .asciiz "\nEnter encryption key (1-9): "
message_prompt: .asciiz "\nEnter message: "
output: .asciiz ""
re_enter: .asciiz "\nWrong input"
buffer: .space 50
.text
main:
# Prints the prompt asking the user if they want to encrypt or decrypt
li $v0, 4
la $a0, encrypt_decrypt # Loads address from the user prompt
syscall
# Takes in E OR D based on user choice
li $v0, 12
syscall
add $t6, $v0, $0
bne $t6, 69, ELSE # Branch to else if inputed value is not E
# Prints the prompt asking the user for a message to either decrypt or
encrypt based on the users previous choice
li $v0, 4
la $a0, message_prompt # Loads address from the users message
syscall
# Takes the users message
li $v0, 8
la $a0, buffer
lb $t0, 0($a0)
li $a1, 48
syscall
la $s2, buffer
# Asks the user for a key from 1-9
li $v0, 4
la $a0, key
syscall
# Takes the users key value from 1-9
li $v0, 5
syscall
add $s0, $v0, $0
la $t0, ($s0) # Loads key
li $t1, 0 # Lower order bit to be toggled
la $t2, ($s2) # Load user message
beq $t6, 69, encrypt # 69 Is the printable ASCII value of "E"
beq $t6, 68, decrypt # 68 is the printable ASCII value of "D"
ELSE:
bne $t6, 68, E_D_VALIDATION # Branch to E_D_VALIDATION if user input is not D
E_D_VALIDATION:
li $v0, 4
la $a0, re_enter
syscall
j main
encrypt:
encrypt_loop:
lb $t3, 0($t2) # Loads character bytes
beq $t3, 10, encrypted # Branches to "encrypted" if we reach the end of a character
add $t3, $t3, $t0
addi $t4, $0, 1
sllv $t4, $t4, $t1
xor $t3, $t3, $t4 # Lower order bit toggle
sb $t3, 0($t2) # Stored encrypted character
addi $t2, $t2, 1
j encrypt_loop # Loops through the list of encrypted characters
encrypted:
li $v0, 4 # Print out encrypted message
la $a0, output
syscall
la $a0, ($s2)
syscall
j exit # Exits the program
decrypt:
decrypted_loop:
lb $t3, 0($t2) # Loads character bytes
beq $t3, 10, decrypted # Branches to "decrypted" if we reach the end of a character
addi $t4, $0, 1
sllv $t4, $t4, $t1
xor $t3, $t3, $t4
sub $t3, $t3, $t0
sb $t3, 0($t2) # Stored decrypted character
addi $t2, $t2, 1
j decrypted_loop # Loops through the list of decrypted characters
decrypted:
li $v0, 4 # Print out decrypted message
la $a0, output
syscall
la $a0, ($s2)
syscall
j exit # Exit the program
exit:
All you're missing is the error handling:
beq $t6, 69, encrypt # 69 Is the printable ASCII value of "E"
beq $t6, 68, decrypt # 68 is the printable ASCII value of "D"
<handle error here>
encrypt:
What to do to handle the error: print a message and quit, or print a message and goto someplace earlier in the code, maybe main or some other new label you introduce for this.
However, it might be nice to check for incorrect input before getting this far, and if you do that you won't have to check so much later: you can check for just E or just D instead of for both, because at this point you know it is only one or the other and nothing else.
So pseudo code you want to put immediately after inputting what should be the E or D:
if ( input != E && input != D ) { print input error message; goto reEnter; }
Where reEnter could be main or another location you choose to go back to get the input.
I would translate this into assembly language using the following series of transformations.
First, if-goto-label style, which skips the if-statement's then part when the condition is false:
if ( ! ( input != E && input != D ) ) goto inputOk;
print input error message
goto reEnter;
inputOk:
; continue with rest of program knowing good input (exactly E or D)
Next: distribute the negation per De Morgan:
if ( ! ( input != E ) || ! ( input != D ) ) goto inputOk;
print input error message
goto reEnter;
inputOk:
; continue with rest of program knowing good input (exactly E or D)
Next: negate the relational operators:
if ( input == E || input == D ) goto inputOk;
print input error message
goto reEnter;
inputOk:
; continue with rest of program knowing good input (exactly E or D)
Next: split the disjunction (||)
if ( input == E ) goto inputOk;
if ( input == D ) goto inputOk;
print input error message
goto reEnter;
inputOk:
; continue with rest of program knowing good input (exactly E or D)
Now, that's pretty easy to write in assembly.

How to fix bad address error in MIPS assembly

I am very new to MIPs programming and have been struggling alone to solve to problem. I am in need of help from people of expertise, to help me through the way.
I am trying to build a program that takes in multiple integer inputs from the console and sort it through mergesort.
The problem is, though I believe logic is right, I keep on facing "Bad address in data/stack read: Ox...." error in the merge phase of the logic.
It would be of great help if you could help.
Thank you in advance.
.data
array: .space 40 # store max up to 10 elements integer array
eol: .asciiz "\n"
mess: .asciiz " Enter 10 numbers to be stored in the array. "
# Some test data
eight: .word 8
five: .word 5
four: .word 4
nine: .word 9
one: .word 1
seven: .word 7
six: .word 6
ten: .word 10
three: .word 3
two: .word 2
# An array of pointers (indirect array)
length: .word 10 # Array length
info: .word seven
.word three
.word ten
.word one
.word five
.word two
.word nine
.word eight
.word four
.word six
.text
main :
la $t0, 0
jal readInput
la $a0, array # Load the start address of the array
lw $t0, length # Load the array length
sll $t0, $t0, 2 # Multiple the array length by 4 (the size of the elements)
add $a1, $a0, $t0 # Calculate the array end address
jal mergesort # Call the merge sort function
# b sortend # We are finished sorting
b prdone
readInput :
slt $t1, $t0, 40
beq $t1, 1, readInputLoop
jr $ra
readInputLoop :
beq $t0, 40, readInput
# Printout the message for input
li $v0, 4
la $a0, mess
syscall
# Receive inputs from the user
li $v0, 5
syscall
sw $v0, array($t0)
li $v0, 1
lw $a0, array($t0)
syscall
# Increment the loop index by 4, and loop again
addi $t0, $t0, 4
b readInputLoop
##
# Recrusive mergesort function
#
# #param $a0 first address of the array
# #param $a1 last address of the array
##
mergesort:
addi $sp, $sp, -16 # Adjust stack pointer
sw $ra, 0($sp) # Store the return address on the stack
sw $a0, 4($sp) # Store the array start address on the stack
sw $a1, 8($sp) # Store the array end address on the stack
sub $t0, $a1, $a0 # Calculate the difference between the start and end address (i.e. number of elements * 4)
ble $t0, 4, mergesortend # If the array only contains a single element, just return
srl $t0, $t0, 3 # Divide the array size by 8 to half the number of elements (shift right 3 bits)
sll $t0, $t0, 2 # Multiple that number by 4 to get half of the array size (shift left 2 bits)
add $a1, $a0, $t0 # Calculate the midpoint address of the array
sw $a1, 12($sp) # Store the array midpoint address on the stack
jal mergesort # Call recursively on the first half of the array
lw $a0, 12($sp) # Load the midpoint address of the array from the stack
lw $a1, 8($sp) # Load the end address of the array from the stack
jal mergesort # Call recursively on the second half of the array
lw $a0, 4($sp) # Load the array start address from the stack
lw $a1, 12($sp) # Load the array midpoint address from the stack
lw $a2, 8($sp) # Load the array end address from the stack
jal merge # Merge the two array halves
mergesortend:
lw $ra, 0($sp) # Load the return address from the stack
addi $sp, $sp, 16 # Adjust the stack pointer
jr $ra # Return
##
# Merge two sorted, adjacent arrays into one, in-place
#
# #param $a0 First address of first array
# #param $a1 First address of second array
# #param $a2 Last address of second array
##
merge:
addi $sp, $sp, -16 # Adjust the stack pointer
sw $ra, 0($sp) # Store the return address on the stack
sw $a0, 4($sp) # Store the start address on the stack
sw $a1, 8($sp) # Store the midpoint address on the stack
sw $a2, 12($sp) # Store the end address on the stack
move $s0, $a0 # Create a working copy of the first half address
move $s1, $a1 # Create a working copy of the second half address
mergeloop:
lw $t0, 0($s0) # Load the first half position pointer
lw $t1, 0($s1) # Load the second half position pointer
###### SOURCE LOCATION OF THE PROBLEM #####
lw $t0, 0($t0) # Load the first half position value
lw $t1, 0($t1) # Load the second half position value
bgt $t1, $t0, noshift # If the lower value is already first, don't shift
move $a0, $s1 # Load the argument for the element to move
move $a1, $s0 # Load the argument for the address to move it to
jal shift # Shift the element to the new position
addi $s1, $s1, 4 # Increment the second half index
noshift:
addi $s0, $s0, 4 # Increment the first half index
lw $a2, 12($sp) # Reload the end address
bge $s0, $a2, mergeloopend # End the loop when both halves are empty
bge $s1, $a2, mergeloopend # End the loop when both halves are empty
b mergeloop
mergeloopend:
lw $ra, 0($sp) # Load the return address
addi $sp, $sp, 16 # Adjust the stack pointer
jr $ra # Return
##
# Shift an array element to another position, at a lower address
#
# #param $a0 address of element to shift
# #param $a1 destination address of element
##
shift:
li $t0, 10
ble $a0, $a1, shiftend # If we are at the location, stop shifting
addi $t6, $a0, -4 # Find the previous address in the array
lw $t7, 0($a0) # Get the current pointer
lw $t8, 0($t6) # Get the previous pointer
sw $t7, 0($t6) # Save the current pointer to the previous address
sw $t8, 0($a0) # Save the previous pointer to the current address
move $a0, $t6 # Shift the current position back
b shift # Loop again
shiftend:
jr $ra # Return
sortend: # Point to jump to when sorting is complete
# Print out the indirect array
li $t0, 0 # Initialize the current index
prloop:
lw $t1,length # Load the array length
bge $t0,$t1,prdone # If we hit the end of the array, we are done
sll $t2,$t0,2 # Multiply the index by 4 (2^2)
lw $t3,array($t2) # Get the pointer
lw $a0,0($t3) # Get the value pointed to and store it for printing
li $v0,1
syscall # Print the value
la $a0,eol # Set the value to print to the newline
li $v0,4
syscall # Print the value
addi $t0,$t0,1 # Increment the current index
b prloop # Run through the print block again
prdone: # We are finished
li $v0,10
syscall
Expected result would be printed integers of a sorted array, but i keep on receiving the error message of
"Exception occurred at PC=0x0040015c Bad address in data/stack read:
0x00000000".

write russian peasant multiplication with mips

i want to write a program that use russian peasant multiplication with mips but i face some problems
/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
int res = 0; // initialize result
// While second number doesn't become 1
while (b > 0)
{
// If second number becomes odd, add the first number to result
if (b & 1)
res = res + a;
// Double the first number and halve the second number
a = a << 1;
b = b >> 1;
}
return res;
}
I translated it in mips with MARS environment
.data
msg1: .asciiz "give your first number"
msg2: .asciiz "give the second number"
.text
#a = $t1
#b = $t2
li $t3,0 #p
li $s1,1
li $s2,2
#display msg1
li $v0,4
la $a0,msg1
syscall
#read first number
li $v0,5
syscall
move $t1,$v0
#display msg2
li $v0,4
la $a0,msg2
syscall
#read second number
li $v0,5
syscall
move $t2,$v0
WHILE:
bgt $t2,$zero,DO
move $a0,$t3
li $v0,1
syscall
li $v0,10
syscall
DO:
div $t2,$s2
mfhi $s0 #r $s0 = $t2 / $s2
beq $s0,$s1,INC # IF b MOD 2 = 1 I jump to INC
#a = 2xa
mul $t1,$t1,$s2
div $t2,$s2
mflo $t2 # b = $t2/$s2
j WHILE
# i = i+ 1
INC:
add $t3,$t3,$t1
jr $ra
please , someone could help me ?
to fix "Error in : invalid program counter value: 0x00000000"
i searched how to fix it but i have a problem with $ra
how to save propertly the return address in $ra ?
the jr $ra will jump to the address stored in register $ra, which was not set by your code, so it is still zero (initial register value from MARS before running your code). The CPU will then jump to address zero, which is failure, and reports that.
To use jr $ra to "return" from some code, you have to first use jal instruction (or other instruction modifying $ra content) to set up $ra. Also when you want to nest several jal "subroutines calls", you have to store/restore the $ra of the outer calls around to not lose the value by the next nested jal.
Following code is example of both using paired jal+jr $ra for "subroutine"-like call, and also example how straightforward the implementation of such algorithm is in assembly (because actually that C source is more like assembly in C, so your inexperience made you take a very convoluted and complex approach of something what can be implemented in assembly almost 1:1 with the original C source):
.text
main: # just minimal "main" to verify the code works
# read two integers as input
li $v0,5
syscall
move $a0, $v0 # $a0 = a
li $v0,5
syscall
move $a1, $v0 # $a1 = b
# call the russianPeasant subroutine
jal russianPeasant # $v0 = a * b
nop
# output result
move $a0, $v0
li $v0, 1
syscall
# terminate
li $v0, 10
syscall
And the subroutine itself, which can be called with arguments in a0 and a1 and returns result in v0.
# input: $a0 = a, $a1 = b
# output: $v0 = a * b
russianPeasant:
li $v0, 0 # res = 0
beq $a1, $zero, russianPeasant_b_zero
nop # neutralize "Delayed branching" setting ("nop" works with both ON/OFF setting)
russianPeasant_while_b:
andi $at, $a1, 1 # test if b is odd, for even b skip the res = res + a
beq $at, $zero, russianPeasant_b_even
nop # but such neutralization comes with performance cost of course
add $v0, $v0, $a0 # res = res + a
russianPeasant_b_even:
sll $a0, $a0, 1 # a = a << 1
srl $a1, $a1, 1 # b = b >> 1
bne $a1, $zero, russianPeasant_while_b # repeat when (b != 0)
nop # on real MIPS production code the instructions are reordered to avoid useless nop
russianPeasant_b_zero:
jr $ra # return res
nop
The code is intentionally putting after each branch nop instruction to make it work with both delayed branching setting ON or OFF.
Try to use MARS help (F1) with instruction description to figure out, how it works, also use the single-step feature of the debugger to watch out the code in action, one instruction at time, observing all the register values and code flow.
On real MIPS CPU with the delayed branching the code can be optimized like this (you can switch "Delayed branching" ON in MARS settings to make it simulate real MIPS CPU with this somewhat confusing behaviour .. from your original source it looks like you are learning the MIPS assembly without delayed branching, which is certainly reasonable approach for somebody just starting with assembly, but that's not how real MIPS CPU works):
# input: $a0 = a, $a1 = b
# output: $v0 = a * b
russianPeasant_real_MIPS: # second variant supporting delayed branching like real MIPS CPU
beq $a1, $zero, russianPeasant2_b_zero
li $v0, 0 # res = 0
russianPeasant2_while_b:
andi $at, $a1, 1 # test if b is odd, for even b skip the res = res + a
beq $at, $zero, russianPeasant2_b_even
srl $a1, $a1, 1 # b = b >> 1
add $v0, $v0, $a0 # res = res + a
russianPeasant2_b_even:
bne $a1, $zero, russianPeasant2_while_b # repeat when (b != 0)
sll $a0, $a0, 1 # a = a << 1
russianPeasant2_b_zero:
jr $ra # return res
nop

How to design a program that finds the sum of the integers from 1 to N, where N is a value read on the keyboard?

This is my first attempt at MIPS and I designed a pseudocode description of a possible algorithm. The code outline is as follows:
main: Print: "Please input a value for N ="
read v0
If(v0 >0)
{
t0 = 0
while(v0 > 0) do
{
t0 = t0 + v0
v0 = v0 +v0 -1
}
print: The sum of integers from 1 to N is = ", t0
go to main
}
else
print: "Honest Abe"
so, with this outline, I made somewhat of an attempt to translate this into MIPS but the whole storing variables and reading them in is confusing me. My attempt of the real code is:
.data
Prompt: .asciiz "\n Please input a value for N="
Result: .asciiz "\n The sum of integers from 1 to N is "
Bye: .asciiz "\n ***Honest Abe***"
.text
main:
li $v0,4 #load $v0 with print_string code
la $a0, Prompt #load $a0 with the message to be displayed
syscall
bgz $v0, else
li $t0, 0
while:
bgz $v0
add $t0,$t0,$v0
addi $v0,$vo -1
From here, I do not understand how the for loops work in MIPS and I do not understand if this is even the correct approach. The whole idea of reading in numbers and then storing the integers isn't processing in my head. Also, I am unsure if I am using the appropriate commands for the loop. Help to any of these questions would be great!
Your algorithm seems a bit odd and too much of a hassle, if I got right what you wanted to do.
You can compute a sum until a certain number with a simple for loop. As in C:
scanf("%d", &num);
for(i=0;i<num;i++)
sum=sum+i;
like an array.
With a little help from the reference card of MARS, you can end up with something like this:
.text
main:
li $v0, 5 #read a number from the keyboard
syscall
addi $s0, $v0, 1 #s0= the number from the keyboard + 1 (the limit)
li $t0, 1 #counter set to 1
loop:
beq $t0, $s0, exit #if the counter becomes equal tothe limit, exit the loop
add $t1, $t1, $t0 #add the counter to the sum to this point
addiu $t0, $t0, 1 #add 1 to the counter for each loop
j loop #go to the "loop" label above
exit:
li $v0, 1
move $a0, $t1
syscall
li $v0, 10
syscall

Resources