Runtime exception at 0x0040002c: address out of range 0x00000001 in MIPS Assembler for ceasar encryption - runtime

The Programm compiles just fine but as soon as i give input this error is thrown:
"Error in line 28: Runtime exception at 0x0040002c: address out of range 0x00000001
Processing terminated due to errors."
Here ist the code for my programm:
.data
line: .space 80
.text
main:
# read line from stdin
li $v0, 8
la $a0, line
li $a1, 80
syscall
# call caesar_line
li $a0, 1
jal caesar_line
# return 0
li $v0, 0
jr $ra
caesar_line:
# save start of line
move $t0, $a0
# loop through line
loop:
# load the character from memory
move $t1, $a0
lb $a0, 0($t1)
beqz $a0, end_loop
jal caesar_char
sb $v0, 0($t1)
addi $t1, $t1, 1
move $a0, $t1
j loop
end_loop:
# print line
li $v0, 4
move $a0, $t0
syscall
jr $ra
caesar_char:
# check if c is lowercase
blt $a0, 'a', upper
bgt $a0, 'z', not_alpha
addi $a1, $a1, 'a'
jal caesar_helper
j done
upper:
# check if c is uppercase
blt $a0, 'A', not_alpha
bgt $a0, 'Z', not_alpha
addi $a1, $a1, 'A'
jal caesar_helper
j done
not_alpha:
# not an alphabetical character
move $v0, $a0
j done
caesar_helper:
# subtract base from c
sub $t0, $a0, $a2 # $t0 = c - base
# add distance + 26 to c
addi $t0, $t0, 26 # $t0 += 26
add $t0, $t0, $a1 # $t0 += distance
# calculate c % 26
li $t1, 26 # $t1 = 26
div $t0, $t1 , $t1 # $lo = c % 26
mflo $t0
# add base to c
add $v0, $t0, $a2 # $v0 = c + base
done:
jr $ra
Not even ChatGBT could find an error.
The code should shift all chars of an string by a certain amount, but as soon as it is run the error above is thrown.

Related

MIPS find end of string

I have the following mips code (running it in QTSPIM), that is supposed to count the number of characters in a string and print them.
The logic behind it is very simple but is does not work as it should. Everything goes well until it reaches the end of the string and then it continues counting even though I compare each element to $zero to find the end of string (\0).
Is there something wrong with my condition to exit the loop, or my_string does not contain \0 in the end so it won't exit?
.data
endl: .asciiz "\n"
my_string: .asciiz "thisisastring"
star: .asciiz "*"
str_end: .word 0
space: .asciiz " "
.text
.globl main
main:
la $a0, my_string
li $v0, 4
syscall
la $a0, endl
li $v0, 4
syscall
la $t0, my_string # load mystring to $t0
li $t1, 0 # make $t1 = 0, character counter
lb $t2, ($t0) # make $t2 point to the first character of "my_string"
li $t3, 1 # $t3 is the ++ register to go to the next character
li $t4, 0 # character counter
la $t5, str_end
cont:
beqz $t0, print # if \0 is found print and exit
addi $t4, $t4, 1 # increase the counter
lbu $a0, ($t0) # print current character
li $v0, 11
syscall
addi $t0, $t0, 1 # go to next char
#move $t2, $t0
j cont
print:
move $a0, $t4
li $v0, 1
syscall
j exit
exit:
li $v0, 10
syscall
The problem is in the order of the instructions, the logic of the code.
Here is the corrected version with no redundant code:
.data
endl: .asciiz "\n"
my_string: .asciiz "thisisastring"
str_end: .word 0
.text
.globl main
main:
la $a0, my_string
li $v0, 4 # print the string
syscall
la $a0, endl # print endl
li $v0, 4
syscall
la $t0, my_string # load mystring to $t0
li $t1, 0 # make $t1 = 0, character counter
lb $t2, 0($t0) # make $t2 point to the first character of "my_string"
la $t5, str_end
cont:
lb $a0, 0($t0) # print current character
beqz $a0, print # if \0 is found print and exit
addi $t1, $t1, 1 # increase the counter
addi $t0, $t0, 1 # go to next char
li $v0, 11
syscall
j cont
print:
move $a0, $t1
li $v0, 1
syscall
j exit
exit:
li $v0, 10
syscall

comparing a string in MIPS

Could someone tell me what is wrong with my code so far. I am trying to make a program that takes input from the user (roman numerals) and then converts it to integers. So far this is what I have:
.data
buffer: .space 20
onlyCaps: .asciiz "Please enter only Capital Numbers\n"
enter1: .asciiz "Number out of range. Please enter another number\n"
enter2: .asciiz "Please enter your roman numeral: "
debug: .asciiz "reach"
M: .asciiz "1000"
D: .asciiz "500"
C: .asciiz "100"
L: .asciiz "50"
X: .asciiz "10"
V: .asciiz "5"
I: .asciiz "1"
.text
main:
la $a0, onlyCaps # "Enter Only Capital numbers"
li $v0, 4
syscall
la $a0, enter2 #prompt user with "Please enter a roman numeral:"
li $v0, 4
syscall
la $a0, buffer #load byte space into address
li $a1, 3 # allot the byte space for string
li $v0, 8 #read user input, j
syscall
li $t4, 1
loop:
lb $t0, 0($a0) # Save $v0 value to $t0
beqz $t4, done # if it is equal to zero end the loop
add $a0, $a0, $t4 #increment the address
j mCheck
#while loop ends here
mCheck:
beq $t0, 'M', mChar # if $t0 equal M go to mChar
bne $t0, $t1, dCheck # move to see if equals D
dCheck:
beq $t0, 'D', dChar # if $t0 equal D go to dChar
bne $t0, $t1, cCheck
cCheck:
beq $t0, 'C', cChar # if $t0 equal C go to cChar
bne $t0, $t1, lCheck
lCheck:
beq $t0, 'L', lChar # if $t0 equal L go to lChar
bne $t0, $t1, xCheck
xCheck:
beq $t0, 'X', xChar # if $t0 equal X go to xChar
bne $t0, $t1, vCheck
vCheck:
beq $t0, 'V', vChar # if $t0 equal V go to vChar
bne $t0, $t1, iCheck
iCheck:
beq $t0, 'I', iChar # if $t0 equal I go to iChar
bne $t0, $t1, error
mChar:
la $a0, M #puts one hundred in $t3
li $v0, 4
syscall
j loop
dChar:
la $a0, D # prints out 500
li $v0, 4
syscall
j loop
cChar:
la $a0, C # prints out 500
li $v0, 4
syscall
j loop
lChar:
la $a0, L # prints out 500
li $v0, 4
syscall
j loop
xChar:
la $a0, X # prints out 500
li $v0, 4
syscall
j loop
vChar:
la $a0, V # prints out 500
li $v0, 4
syscall
j loop
iChar:
la $a0, I # prints out 500
li $v0, 4
syscall
j loop
error:
la $a0, enter1 # Print error meg. then back to main
li $v0, 4
syscall
j done
done:
li $v0, 10 # Exit
syscall
My question is how can you take input from the user and put it in $a0, and then use a while loop after that? I can't get the bytes to go to the next spot (i.e. MXX to go from M to X.) currently the program reads M, but not X. Eventually I will switch the program to sum these numbers and to also check to see if the number before is less (i.e. IV) to account for those roman numerals but I need help with the while loop first.

Asm program... something goes wrong

I load two arrays. I have to return a third array that contain the sum of the two and has the dimension of the smaller. Print the last one.
Example:
INPUT: Array1: [1 2 3 4 5] Array2: [2 6 1]
OUTPUT: Array3: [3 8 4]
Program runs... it give me the exact number of elements but every element is 0.
.data
vett1: .word 0:100
vett2: .word 0:100
vett3: .word 0:100
x: .word 0
space: .asciiz " "
.text
.globl main
main:
la $a0, vett1
la $a1, vett2
la $a2, vett3
la $a3, x
li $t0, 0
li $t1, 0
li $t2, 0
jal loadA1 #mi salvo 26 salto a caricavettore1
jal loadA2 #mi salvo 27 salto a caricavettore2
jal lenght #mi salvo 28 salto a controllalunghezza
lw $t2, ($a3)
lw $t3, ($a3)
la $a0, vett1
la $a1, vett2
la $a2, vett3
jal summ
jal print
li $v0, 10
syscall
loadA1:
li $v0, 5
syscall
beq $v0, -1, exit
sw $v0, ($a0)
addi $t0, $t0, 1
addi $a0, $a0, 4
j loadA1
exit: jr $ra
loadA2:
li $v0, 5
syscall
beq $v0, -1, exit2
addi $t1, $t1, 1
sw $v0, ($a1)
addi $a1, $a1, 4
j loadA2
exit2: jr $ra
lenght:
blt $t0, $t1, cond1
sw $t1, ($a3)
jr $ra
cond1: sw $t0, ($a3)
jr $ra
summ:
subi $sp, $sp, 4
sw $ra, 0($sp)
bnez $t2, rec
j exit3
rec: lw $s0, ($a0)
lw $s1, ($a1)
add $v0, $s0, $s1
sw $v0, ($a2)
addi $a0, $a0, 4
addi $a1, $a1, 4
addi $a2, $a2, 4
subi $t2, $t2, 1
jal summ
exit3:
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra
print:
beqz $t3, exit4
lw $a0, ($a2)
li $v0, 1
syscall
la $a0, space
li $v0, 4
syscall
addi $a2, $a2, 4
subi $t3, $t3, 1
j print
exit4: jr $ra
When you sum the two arrays you add 4 to $a2 at the end of each iteration to point it to the next element of vett3. So after the summing is complete $a2 will point to the first memory location after the end of vett3.
Then you call print but don't reset $a2 to point at the start of vett3, so you end up printing garbage data (which could happen to be all zeroes - or mostly zeroes at least, since x and space will be there).

Printing to Screen in MARS for MIPS program

Hi I have to write a program in MIPS that does a bubble sort and then prints the sorted array and plays a note(s). I am having trouble getting it to execute in Mars and I am wondering what I need to add to my program:
.include "ec2_data.asm" # load values into array
add $s0, $zero, 0x10010000
add $t0, $zero, 0x10010000 #how many times to loop
addi $t1, $zero, 0 #initilize the counter
addi $t2, $zero ,0 #initilize position x
addi $t3, $zero, 4 #initilize position y
lw $s2, $t3($s0) #get second position of $s0=y
LOOP:
addi $t0, $t0, -1 #subtract one from the counter
slt $t4, $s1, $s2 #t4 set to 1 if x > y
beqz $t4, BREAK #if t0 is zero (x<y) we dont' have to sort, so go to break
# sort:
add $t5, $zero, $s1 #temp. stores the value of x in t5
add $s1, $zero, $s2 #moves the value of y into x
add $s2, $zero, $t5 #moves the value of x into y
sw $s1, $t2($s0) #save the new x to register
sw $s2, $t3($s0) #save the new y to register
j BREAK
BREAK:
#in here: check to see if we have reached the end
#if not, increment t2 and t3 by 4 to get the next values and jump back to loop to go again
beq $t0, $zero, END #if we are done with the array, go to end
addi $t2, $t2, 4
addi $t3, $t3, 4
j LOOP #jump back to loop again
END:
li $v0, 1 # print integer
syscall
addi $a0, $0, 0xA # load line code into register
addi $v0, $0, 0xB # print new line
syscall
addi $v0, $zero, 33 # midi out synchronous
addi $a0, $zero, 60 # Middle-C
addi $a1, $zero, 250 # ms
addi $a2, $zero, 120 # some instrument
addi $a3, $zero, 64 # some volume
add $a0, $t7, $zero # load value into $a0
syscall # play note!
addi $t6, $t6, 4 # shift memory location by 32 bits
addi $s1, $s1, 1 # increment counter ++
j loop # loop
Exit:
li $v0, 10 # load exit code
syscall # exit
If by "having trouble getting it to execute", you mean it acts strange with the .include file, then you might not have a required option checked in MARS. Go to the Settings menu and check the box for "Initialize Program Counter to global Main if defined". That seems to be something that has to be in effect for included files to work - and for some reason, it isn't turned on by default.

Case sorting in mips

I have a program that will capitalize all lowercase letters and lowercase all the uppercase letters entered in a string by the user. It does this by adding or subtracting 32 from the character value to get the desired character. My problem is that it doesn't change anything in the string. Any suggestions on what to change?
.data
prompt: .asciiz "\n\nEnter an string of characters: "
result: .asciiz "\n\nHere is the string you entered: "
after_sort: .asciiz "\n\nHere is the string after the case sorting: "
buffer: .space 80
.text
main:
#Prints the prompt string
li $v0, 4
la $a0, prompt
syscall
#reads string from user and saves in $a0
li $v0, 8
la $a0, buffer
li $a1, 80
syscall
#Prints the result string
li $v0, 4
la $a0, result
syscall
#Prints the string entered by the user
la $a0, buffer
li $v0, 4
syscall
li $t0, 0 # t0 = i = 0
for_loop:
slti $t1, $t0, 80 # t1 = 1 if and only if t0 < 80
beq $t1, $0, for_loop_done
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
addi $t0, $t0, 1
j for_loop
for_loop_done:
#Prints the result string
li $v0, 4
la $a0, after_sort
syscall
#Prints the string entered by the user
la $a0, buffer
li $v0, 4
syscall
exitProgram: li $v0, 10 # system call to
syscall # terminate program
You are using $a0as a character, such as here:
slti $t2, $a0, 91
but it is never filled with the character. At the moment, it contains a memory address, not a character.
You should load the character using lb and store it back after making it upper/lowercase using sb.
Feel free to add a comment if you want a code example.
Edit: the changes in the relevant part of the code:
...
li $t0, 0 # t0 = i = 0
for_loop:
slti $t1, $t0, 80 # t1 = 1 if and only if t0 < 80
beq $t1, $0, for_loop_done
lb $t4, 0($a0)
beqz $t4, for_loop_done
beq $t4, 10, for_loop_done
slti $t2, $t4, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $t4, $t4, 32 #adds 32 to the character value to lowercase it
j done
lower:
addi $t4, $t4, -32 #subtracts 32 from the character value to capitalize it
done:
addi $t0, $t0, 1
sb $t4, 0($a0)
addi $a0, $a0, 1
j for_loop
for_loop_done:
#Prints the result string
...
It's easy to forget that in assembly, you can't do this:
if something
do this
else
do that
There is no "else", only shudder Goto.
So in this code:
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
addi $t0, $t0, 1
When you branch to upper, it adds 32. Then it subtracts 32, because execution progressed to the next line. So your code capitalizes lower case, but does nothing to uppercase.
You need to add a jump to the first instruction after your if/then/else equivalent:
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
j done # No, I don't want to subtract it again!
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
done:
addi $t0, $t0, 1
In fact, you should probably get rid of the bne altogether - it's redundant. If beq doesn't branch, then it's not equal. So this would be the finished product:
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
# Otherwise, it's lower
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
j done
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
done:
addi $t0, $t0, 1
Hope that helps!
(Edit: #Patrik is right too, you need to "dereference" $a0. My example doesn't take that into account.)
here is my code:
it works perfectly
.data
theString:
.space 20
prompt: .asciiz "Enter a string of characters: "
.text
main:
li $v0, 4
la $a0, prompt
syscall
li $v0, 8
la $a0, theString
li $a1, 20
syscall
li $v0, 4
syscall
la $t1,theString
for: lb $a0, 0($t1)
beqz $a0,out #to find out end of string
beq $a0,10,out #to find out end of string
slti $t2, $a0,91 #if $a0<91 $t2=1
beq $t2,1,small
beq $t2,0,capital
capital:
subu $a0, $a0, 32
li $v0,11
syscall
addi $t1,$t1,1
j for
small:
addi $a0, $a0, 32
li $v0,11
syscall
addi $t1,$t1,1
j for
out:
li $v0, 10
syscall

Resources