Trying to write a basic main program using a function - c

I am trying to write a function to copy words from source memory to destination memory.
I have written the function but I am having difficulty executing the code.
It is giving me execption 4 as an error
.data
.text
main:
.setnoreorder
top: beq $a2,0,done
lw $t1,($a0)
sw $t1,($a1)
add $a0,$a0,4
add $a1,$a1,4
j top
sub $a2,$a2,1
done:
jr $ra #return to the main program
add $0, $0, $0 #nop
I want to write a main program which calls this function to copy 800 words from
address 0x50000 to 0x90000 in memory. But when I add the values in $a0-$a2 and run the code it doesnt work.
Does anyone know how to fix it. (I am converting C code to MIPS which is why I have included a C tag
Cheers

.text # code starts here
main: # required label
la $a0,dest # point to destination
la $a1,srce # point to source
li $a2,1000 # move this many words
jal block_copy # call the routine
nop
li $v0,10
syscall
###############################################################################
# block copy - moves $a3 words from $a1 to $a0
#
# register usage:
# $a0 address of destination
# $a1 address of source
# $a2 block size (number of words to move)
# $v0 return code (0 means no troubles)
#
block_copy:
move $v0,$a2 # counter/rc
bc_loop:
lw $t0,0($a1) # no DMA here
sw $t0,0($a0) # we have to move a word at a time
addiu $a0,$a0,4 # point to next word in destination
addiu $a1,$a1,4 # point to next word in source
addiu $v0,$v0,-1 # decrement counter
bgtz $v0,bc_loop # keep on moving if counter is positive
jr $ra # return to caller
###############################################################################
.data
dest:
.word 9:1000 # destination 1000 words (all zeroes)
srce:
.word 0:1000 # source 1000 words (all nines)

Shouldn't that be:
sub $a2,$a2,1
j top

You show a delay slot in two places, here
j top
sub $a2,$a2,1
and here
done:
jr $ra #return to the main program
add $0, $0, $0 #nop
But apparently not here:
top: beq $a2,0,done
lw $t1,($a0)
Maybe the problem is that the load following the beq is, in fact, a delay slot and is being executed even when $a2 is zero (and the branch is taken) - you are loading from memory at ($a0) even when the count is zero - perhaps accessing invalid memory and causing the exception.

Related

I can’t figure out why my code is not displaying palindromes. Is is saying NO for everything when it should be saying Yes if it’s a palindrome

.org 0x10000000
# Initializations
# NOTE: You may add initializations after line 10, but please do not
# remove or change the initializations to $sp, $s0, $s1, or $s2
li $sp, 0x10fffffc # Starting address of empty stack
li $s0, 0xf0000000 # UART base address
li $s1, array_ptr # Array head pointer
li $s2, array_ptr # Array tail pointer
li $t8 0x00000000
####################################################################
# Do not make changes to the jump to main, the allocation of
# memory for the array, or the main loop
####################################################################
j main
nop
array_ptr: # Label pointing to 100 word array
.space 100
main:
jal poll_UART
nop
jal period_check
nop
jal space_check
nop
jal case_check
nop
jal array_push
nop
j main
nop
####################################################################
# ******************************************************************
####################################################################
# The "poll_UART" function should poll the status register of the UART.
# If the 2^1 bit position (ready bit) is set to 1 then it
# should copy the receive buffer's value into $v0 and send
# a clear status command (2^1) to the command register before
# returning (a return statement is already included). In order to
# receive full credit, $s0 must contain the base address of the UART
# and must be used with the appropriate offsets to access UART
# registers and buffers
poll_UART:
lw $t1, 4($s0)
li $t2, 0b10
and $t3, $t1, $t2
beq $t3, $0, main
nop
lw $v0, 8($s0)
sw $t2, 0($s0)
jr $ra
nop
# The "period_check" function should check if the current character ($v0)
# is a period ("."). If it is a period then the function should go to the
# label, "palindrome_check". If the character is not a period then it
# should use the included return.
period_check:
li $t0, 0x2E
beq $v0, $t0, palindrome_check
nop
jr $ra
nop
# The "space_check" function should check if the current character ($v0)
# is a space (" "). If it is then it should jump to "main" so
# that it skips saving the space character. If not it should
# use the included return.
space_check:
li $t4, 0x20
beq $t4, $v0, main
nop
jr $ra
nop
# The "case_check" function should perform a single inequality check.
# If the current character ($v0) is greater than the ASCII value of 'Z',
# which indicates the current character is lowercase, then it should convert
# the value of $v0 to the uppercase equivalent and then return. If the
# current character ($v0) is already uppercase (meaning the inequality
# mentioned before was not true) then the function should return without
# performing a conversion.
case_check:
li $t5, 0x5A
slt $t6, $v0, $t5
li $t7, 1
beq $t6, $t7, change_uppercase
change_uppercase:
addiu $v0, $v0, -32
jr $ra
nop
# The "array_push" function should save the current character ($v0) to the
# current location of the tail pointer, $s2. Then it should increment the
# tail pointer so that it points to the next element of the array. Last
# it should use the included return statement.
array_push:
sw $v0, 0($s2)
addiu $s2, $s2, 4
jr $ra
nop
# The "palindrome_check" subroutine should be jumped to by the period
# check function if a period is encountered. This subroutine should contain
# a loop that traverses the array from the front towards the back (using the
# head pointer, $s1) and from the back towards the front(using the tail
# pointer, $s2). If the string is a palindrome then as the array is traversed
# the characters pointed to should be equal. If the characters are not equal
# then the string is not a palindrome and the print function should be used
# to print "No". If the pointers cross (i.e. the head pointer's address is
# greater than or equal to the tail pointer's address) and the compared
# characters are equal then the string is a palindrome and "Yes" should be
# printed.
#
# Remember to restore the head and tail pointers to the first element
# of the array before the subroutine jumps back to main to begin processing the
# next string. Also, keep in mind that because the tail pointer is updated at
# the end of "array_push" it technically points one element past the last
# character in the array. You will need to compensate for this by either
# decrementing the pointer once at the start of the array or using an offset
# from this pointer's address.
palindrome_check:
addiu $s2, $s2, -8
move $s3, $s1
subu $s4, $s2, $s3
beq $s4, $0, palindrome
nop
check_loop:
lw $s5, 0($s3)
lw $s6, 0($s2)
bne $s6, $t5, not_palindrome
nop
adjust_pointers:
addiu $s2, $s2, -4
addiu $s3, $s3, 4
slt $t8, $s3, $s2
bne $t8, $0, check_loop
nop
j palindrome
nop
palindrome:
li $a0, 1
call project3_print
move $s2, $s1
j main
nop
not_palindrome:
li $a0, 0
call project3_print
move $s2, $s1
j main
nop
I have tried working on debugging the Palindrome check and everything under that but it all appears fine. Im not sure if the problem remains in the poll_uart or not. this is the template I was given.
When I type in racecar it says no. when I type in gn. it says yes. when I type in night. it says no. So I am just confused.

UART Palindrome checker sending back "no" result all the time

I am working on a project which checks if a word is a palindrome and sends back "yes" or "no". For example the input "abba. data. abcd. reviver." should read "yes" "no" "no" "yes". Instead what I get is all "no". I have done some debugging and from what I can tell I am missing something in the palindrome_loop that is saying everything is not a palindrome. I am very new to all this so I am sorry if I sound uneducated in all this and kind of lost, but I am unsure of what else to do next any guidance or feedback is appreciated.
I am using PLPtool
Below is my code:
.org 0x10000000
# Initializations
# NOTE: You may add initializations after line 10, but please do not
# remove or change the initializations to $sp, $s0, $s1, or $s2
li $sp, 0x10fffffc # Starting address of empty stack
li $s0, 0xf0000000 # UART base address
li $s1, array_ptr # Array head pointer
li $s2, array_ptr # Array tail pointer
####################################################################
# Do not make changes to the jump to main, the allocation of
# memory for the array, or the main loop
####################################################################
j main
nop
array_ptr: # Label pointing to 100 word array
.space 100
main:
jal poll_UART
nop
jal period_check
nop
jal space_check
nop
jal case_check
nop
jal array_push
nop
j main
nop
####################################################################
# ******************************************************************
####################################################################
# The "poll_UART" function should poll the status register of the UART.
# If the 2^1 bit position (ready bit) is set to 1 then it
# should copy the receive buffer's value into $v0 and send
# a clear status command (2^1) to the command register before
# returning (a return statement is already included). In order to
# receive full credit, $s0 must contain the base address of the UART
# and must be used with the appropriate offsets to access UART
# registers and buffers
poll_UART:
lw $t1, 4($s0)
li $t2, 0b10
and $t3, $t2, $t1
beq $t3, $zero, main
nop
lw $v0, 8($s0)
sw $t2, 0($s0)
jr $ra
nop
# The "period_check" function should check if the current character ($v0)
# is a period ("."). If it is a period then the function should go to the
# label, "palindrome_check". If the character is not a period then it
# should use the included return.
period_check:
li $t0, 0x2E
beq $v0, $t0, palindrome_check
nop
jr $ra
nop
# The "space_check" function should check if the current character ($v0)
# is a space (" "). If it is then it should jump to "main" so
# that it skips saving the space character. If not it should
# use the included return.
space_check:
li $t4, 0x20
beq $t4, $v0, main
jr $ra
nop
# The "case_check" function should perform a single inequality check.
# If the current character ($v0) is greater than the ASCII value of 'Z',
# which indicates the current character is lowercase, then it should convert
# the value of $v0 to the uppercase equivalent and then return. If the
# current character ($v0) is already uppercase (meaning the inequality
# mentioned before was not true) then the function should return without
# performing a conversion.
case_check:
li $t5, 0x5A
slt $t6, $v0, $t5
li $t7, 1
beq $t6, $t7, convert_lowercase
nop
convert_lowercase:
addiu $v0, $v0, -32
jr $ra
nop
# The "array_push" function should save the current character ($v0) to the
# current location of the tail pointer, $s2. Then it should increment the
# tail pointer so that it points to the next element of the array. Last
# it should use the included return statement.
array_push:
sw $v0, 0($s2)
addiu $s2, $s2, 4
jr $ra
nop
# The "palindrome_check" subroutine should be jumped to by the period
# check function if a period is encountered. This subroutine should contain
# a loop that traverses the array from the front towards the back (using the
# head pointer, $s1) and from the back towards the front(using the tail
# pointer, $s2). If the string is a palindrome then as the array is traversed
# the characters pointed to should be equal. If the characters are not equal
# then the string is not a palindrome and the print function should be used
# to print "No". If the pointers cross (i.e. the head pointer's address is
# greater than or equal to the tail pointer's address) and the compared
# characters are equal then the string is a palindrome and "Yes" should be
# printed.
#
# Remember to restore the head and tail pointers to the first element
# of the array before the subroutine jumps back to main to begin processing the
# next string. Also, keep in mind that because the tail pointer is updated at
# the end of "array_push" it technically points one element past the last
# character in the array. You will need to compensate for this by either
# decrementing the pointer once at the start of the array or using an offset
# from this pointer's address.
palindrome_check:
addiu $s2, $s2, -8
move $s3, $s1
subu $s6, $s2, $s3
beq $s6, $zero, palindrome
nop
palindrome_loop:
lw $s4, 0($s3)
lw $s5, 0($s2)
bne $s5, $t0, not_a_palindrome
nop
pointer_adjust:
addiu $s2, $s2, -4
addiu $s3, $s3, 4
slt $t8, $s3, $s2
bne $t8, $t0, palindrome_loop
nop
j palindrome
nop
palindrome:
li $a0, 1
call project3_print
move $s2, $s1
j main
nop
not_a_palindrome:
li $a0, 0
call project3_print
move $s2, $s1
j main
nop

Finding factorial of a number using recursive call in MIPS programming

This is the C source code
#include <stdio.h>
int main() {
printf("The Factorial of 10 is %d\n", fact(10));
}
int fact(int n) {
if (n < 1)
return (1);
else
return (n * fact(n - 1));
}
I am converting a C Programming function to a MIPS, but when I run the MIPS program I am getting an error for the .ascii section.
.text
.globl main
main:
subu $sp,$sp,32 # Stack frame is 32 bytes long
sw $ra,20($sp) # Save return address
sw $fp,16($sp) # Save old frame pointer
addiu $fp,$sp,28 # Set up frame pointer
li $a0,10 # Put argument (10) in $a0
jal fact # Call factorial function
la $a0,$LC # Put format string in $a0
move $a1,$v0 # Move fact result to $a1
jal printf # Call the print function
lw $ra,20($sp) # Restore return address
lw $fp,16($sp) # Restore frame pointer
addiu $sp,$sp,32 # Pop stack frame
jr $ra # Return to caller
.rdata
$LC:
.ascii “The factorial of 10 is %d\n\000”
.text
fact:
subu $sp,$sp,32 # Stack frame is 32 bytes long
sw $ra,20($sp) # Save return address
sw $fp,16($sp) # Save frame pointer
addiu $fp,$sp,28 # Set up frame pointer
sw $a0,0($fp) # Save argument (n) to use for Recursive Call
lw $v0,0($fp) # Load n
bgtz $v0,$L2 # Branch if n > 0
li $v0,1 # Return 1
jr $L1 # Jump to code to return
$L2:
lw $v1,0($fp) # Load n
subu $v0,$v1,1 # Compute n - 1
move $a0,$v0 # Move value to $a0
jal fact # Call factorial function
lw $v1,0($fp) # Load n
mul $v0,$v0,$v1 # Compute fact(n-1) * n
$L1: # Result is in $v0
lw $ra, 20($sp) # Restore $ra
lw $fp, 16($sp) # Restore $fp
addiu $sp, $sp, 32 # Pop stack
jr $ra # Return to caller
It's giving me an error for the .ascii code section saying it shouldn't be in the .text:
Error in ".ascii" directive cannot appear in text segment
It's also saying that:
"$L1": operand is of incorrect type
It's giving me an error for the .ascii code section saying it shouldn't be in the .text:
Error in ".ascii" directive cannot appear in text segment"
I am going out on a limb here because I am not 100% sure what you are running this on, but some sims like MARS don't recognize the rdata segment. You can try using just .data.
Also, if you are on something like WinMIPS64, you may want to try placing the .data segment at the top of the code. I understand what you are doing is right in some environments and but doesn't work in others, so give it a whirl.
May I suggest you try these things separately, just in case.

Understanding opening and reading a file in assembly

I've got a project for a class in which we have to transform a picture using sobel operators in assembly, and I'm having a bit of a problem understanding some example code.
In the data segment and in the main function is everything that's need to make the function work (The code works, I just don't understand why).
The bit I don't understand is the use of the li command to change the values of the $aregisters.
read_rgb_image:
# Place file and size in register,
move $s0, $a0 #file name
move $s1, $a1 #buffer
move $s2, $a2 #buffersize
# Open file
move $a0, $s0 # File's directory/name
li $a1, 0 #THIS LI ARE THE COMMANDS I DON'T UNDERSTAND
li $a2, 0 # Read life
li $v0, 13 # Option for opening file
syscall
# Read file
move $a0, $v0 # File descriptor
move $a1, $s1 # Buffer with result
move $a2, $s2 # Space of information to read
li $v0, 14 # Read file
syscall
# Store read buffer
move $s1, $v0
# Close file
li $v0, 16 # Close file
syscall
# Return
move $v0, $s1 # Make return
jr $ra
nop
Can somebody please explain this to me?!
The LI instruction loads an numeric value into a register. Before you make a system call, you need to load the $v0 register with the number assigned to the system service. You also need to load argument registers with system service specific parameters. Without the documentation, we can only guess (beyond the comments in the code) why the specific values being loaded into the registers. However, that is what is going on.
We can guess that you are calling the 4-paremeter version of the open function and that your specifing the file name, mode=0, and flags=0 using the argument registers.
MIPS defines pseudoinstructions that are not actually part
of the instruction set but are commonly used by programmers and compilers.
load immediate li is a pseudoinstruction it loads a 32-bit constant using a combination of lui and ori instructions.
The following instructions are equivalent.
MIPS instruction
lui $s0, 0x1234
ori $s0, 0xAA77
pseudoinstruction
li $s0, 0x1234AA77

How can I store sequence in an array in MIPS?

I have this homework problem .
Write a program that produces the following sequence; 1,2,2,4,8, 32, 256,… and stores it in an array, depending on the number of terms chosen by the user. Each element in the sequence can be calculated by multiplying the two elements preceding it. In other words the nth sequence number Sn is calculated by the equation Sn=Sn-1×Sn-2.
I tried but it didn't run
My code
^
^
# UNTITLED PROGRAM
.data # Data declaration section
str1: .ascii "Please enter the number of terms to produce: "
arr: .space 40
.text
main: # Start of code section
li $v0, 4 # system call code for printing string = 4
la $a0, str1 # load address of string to be printed into $a0
syscall # call operating system to perform print operation
li $v0, 5 # get ready to read in integers
syscall # system waits for input
move $s0,$v0 # store the result of the read (returned in $v0) in num1
la $s1,arr
addi $t2,$zero,2 # i=2
addi $t0,$zero,1
add $t1,$t0,$t0
sw $t0,0($s1)
sw $t1,0($s1)
L1:
addi $t2,$t2,1 #i++
addi $s1,$s1,4
lw $t4,0($s1) #A[i-1]
lw $t5,4($s1)
mul $t3,$t4,$t5
sw $t3,8($s1)
beq $t2,$s0,print
j L1
print:
lw $t3,0($s1)
li $v0, 1 # system call code for print_int
move $a0, $t3 # integer to print
syscall # print it
addi $s1,$s1,4
beq $t2,$s0,Exit
j print
Exit:
li $v0, 10 # exits program
syscall
# END OF PROGRAM
MARS error message:
Error in line 26: Runtime exception at 0x00400030:
store address not aligned on word boundary 0x1001002d
The error message is telling you that you're trying to access memory with an illegal (non word-aligned) address at this instruction:
sw $t0,0($s1)
When you have problems like this, you need to use the debugger. First, set a break point at the instruction where the exception is thrown.
Run the program, and when it stops at the break point, check the address (in $s1) you're trying to access. You'll see that it's 268501037 or 0x1001002d, and since it ends with a 7, it's not word-aligned.
$s1 has the correct array address, but I think you're assuming that when you created the array in the data segment, that it would start at a word-aligned address. This is not the case. To resolve this, you need to align the data.
.data # Data declaration section
str1: .ascii "Please enter the number of terms to produce: "
.align 2
arr: .space 40

Resources