Related
I am trying to print on the console the values of the array, which are already given as intA in .data. I.e., trying to print values of an array without user's prompt.
My code:
.data
prompt: .asciiz "The values in the array are:\n"
finished: .asciiz "\nNo more values to present"
space: .asciiz " "
intA: .word 11, 2, 3, 4, 5, 34, 0
.text
.globl main
main:
#Prints the prompt string
li $v0, 4
la $a0, prompt
syscall
# initialization of a0, a1, and t3 (i, counter)
la $a0, intA # loading starting address (base) of array in register a0
addi $a1, $zero, 6 # array size - 1
addi $t3, $zero, 0 # i initialized to 0
j loop
loop:
lw $t1, 0($a0) # loading integer (value of array) in the current address to register t1, I use lw because integer is a word (4 bytes)
# printing current value of array
li $v0, 4
la $a2, ($t1)
syscall
# spacing between values
li $v0, 4
la $a2, space
syscall
# checking that next address is not outside of the array
addi $t3, $t3, 1
slti $t2, $t3, 6
bne $t2, 1, done
# accessing next integer and jumping back to print it
addi $a0, $a0, 4
j loop
done:
# indicating program is done
li $v0, 4
la $a0, finished
syscall
The output that I am getting: output
Any idea why it doesn't print the values of the array, and also what are these squares that are printed instead?
Edit:
I changed
# printing current value of array
li $v0, 4
la $a2, ($t1)
syscall
to
# printing current value of array
li $v0, 1
lw $a2, ($t1)
syscall
Because, from what I understand, I print an integer so $v0 should be fed 1, and I should lw and not la (because it is an integer, i.e, a word)
However, now I get a runtime error in line 31: lw $a2, ($t1) Telling me that
fetch address not aligned on word boundary 0x0000000b
Solution: Instead of lw $a0, ($t1) for printing the value of $t1, I need to do add $a0, $t1, $zero, because I am trying to use the value and not to access an address.
This is my first time coding PCSPIM. I find that there is a little trouble with my code.
.data
user_input: .asciiz "\n\nEnter an Integer for the value of n: "
result_display: .asciiz "\nThe sum from 0 to n is "
Greeting: .asciiz "\n\nThank you!"
.text
main:
#user input
li $v0, 4
la $a0, user_input
syscall
#allow user input
li $v0, 5
syscall
#store the input value into t8
move $t8, $v0
#calculation
addi $s0, $zero, $t8
I wish to use the integer value ($t8) that users input into the #calculation section, but it ends up with error.
addi $t0, $zero, 0
loop1:
add $t0, $t0, $s0
addi $s0, $s0, -1
bne $s0, $zero, loop1
nop
nop
# Display the result
li $v0, 4
la $a0, result_display
syscall
# Print out the result
li $v0, 1
move $a0, $t0
syscall
# Greets the user
li $v0, 4
la $a0, Greeting
syscall
# Exit the program
li $v0, 10
syscall
Sorry for my broken English.
The error is in the way you are using the "addi" instruction. The instruction requires an immediate (number) value to be passed as the third operand and not an architectural register. If you update the "addi" instruction to "addu" the code should work.
The current code that I have looks as such. It can successfully read if a string is a palindrome when punctuation is not entered.
.data
buffer: .space 80
input: .asciiz "Enter a string: "
output: .asciiz "Your string: "
paly: .asciiz "This is a palindrome "
notp: .asciiz "This is not a palindrome"
.text
main:
li $v0, 4 # system call code for print_str
la $a0, input # address of string to print
syscall # print the input
li $v0, 8 # code for syscall read_string
la $a0, buffer # tell syscall where the buffer is
li $a1, 80 # tell syscall how big the buffer is
syscall
la $a0, buffer # move buffer into a0
li $v0, 4 # print buffer
syscall
la $t1, buffer # begining of the string
la $t2, buffer # end of the string
li $t0, 0
loop:
lb $t3,($t2) # load the byte of the end of the string
beqz $t3,endl # if its equal to 0 then branch out of the loop
addu $t2, $t2,1 # if in loop the increment to next character
jal loop # repeat the loop
upper:
addi $t4,$t4,32
j lowered
lowered:
addi $t0,$t0,1
sb $t4, 0($a0)
addi $a0,$a0,1
j loop
endl:
subu $t2, $t2, 2 # subtracting 2 to move back from \0 and \n
check:
#lb $t4, 0($a0)
#beqz $t4, after
#beq $t4, 10, after
#slti $t2, $t4, 91
#li $t3, 1
#beq $t2, $t3, upper
bge $t1, $t2, palindrome # if both sides are equal then its a palindrome
# call palindrome
lb $t3, ($t1) # load the byte into register t3
lb $t4, ($t2) # load the end byte into register t4
bne $t3, $t4, notpaly # if the two register bytes are not equal its it not a palindrome
addu $t1, $t1, 1 # increment the beginning of the string to next char
subu $t2, $t2, 1 # decrement end of string to next char to compare
jal check # repeat the loop
palindrome:
la $a0, paly # calling paly from data
li $v0, 4 # call for reading string
syscall
jal exit # jump to end
notpaly:
la $a0,notp # calling notp from data
li $v0, 4 # call for reading string
syscall
jal exit # jump to end
after:
li $v0, 4
la $a0, output
syscall
la $a0, buffer
li $v0, 4
syscall
exit:
li $v0 ,10 # call to end program
syscall # call os
Now I know I need to implement code such as to make uppercase lowercase, and to remove punctuation.
With my already stored bits in check: I have some commented code, and this would be to to test if a character is uppercase, then jump to the function and lower it by adding 32. But it does not compile correctly and i am assuming this is because I am not storing the bits correctly.
#lb $t4, 0($a0)
#beqz $t4, after
#beq $t4, 10, after
#slti $t2, $t4, 91
#li $t3, 1
#beq $t2, $t3, upper
My code has two parts; the first part is making a function that takes in two numbers and return their products. I believe I did this part right.
The second part is where I'm not sure what's the problem is. In this part I need to make a function that find the factorial number, and within this function, I have to use the multiplication function which I made in the first part. Please have a look at my code and tell me what am I doing wrong.
.data
Fa_message: .asciiz "\nFAIL TEST\n"
Pa_message: .asciiz "\nPASS TEST\n"
number1: .word 4
number2: .word 5
KnownAnswers: .word 20
START: .word 16
.text
main:
# taking in the numbers for calculation.
lw $a0, number1 # $a0 =4
lw $a1, number2 # $a1 =5
lw $t0, KnownAnswers # $t0 =20
jal func_multiply # calling the mulyiply function
move $t4,$v0 # store the product for any further comparisons
bne $t0, $t4, FailT # did it fail the test?
beq $t0, $t4, PassT # did it pass the test?
func_multiply: # the mulyiply function
mul $v0, $a0, $a1 # $v0 = number1 * number2
jr $ra
FailT: # print "\nFAIL TEST\n"
li $v0,4
la $a0, Fa_message
syscall
PassT: # print "\nPASS TEST\n"
li $v0,4
la $a0, Pa_message
syscall
###---------------------(PART-2)-------------------
lw $a0, number1 # load the number for the factorial procedure
beq $a0, $zero, factorialDone # (if the number = 0), !0 = 1
mul $a1, $a1, $zero # initializing $a1
mul $a2, $a1, $zero # initializing $a2
addi $a1, $a0, -1 # $a1 = (the entered number - 1)
addi $a2, $a0, 0 # $a2 = the entered number
jal findfactorial
###
#Stop
li $v0, 10
syscall
findfactorial:
jal func_multiply # calling the mulyiply function # mul $v0, $a0, $a1 # $v0 = number1 * number2
move $t4,$v0 # store the product in t4 for any further usage
addi $a0, $a0, -1 # $a1 = $a1-1
addi $a1, $a0, -1
bne $a1, $zero, findfactorial # enter a loop if $a1 does not equal 0
jr $ra
factorialDone:
addi $v0, $v0, 1
syscall
The jal instruction modifies the $ra register. So if function A calls a function B, then A has to save and restore the value that $ra had when entering A so that it can return to the correct place. This is typically done using the stack as temporary storage.
You can push a register on the stack (save it) like this:
addi $sp, $sp, -4
sw $ra, ($sp)
And pop a register off the stack (restore it) like this:
lw $ra, ($sp)
addi $sp, $sp, 4
Then there's your findfactorial loop. You're discarding the result of all the previous iterations, so your result will always be 1*2 == 2. The loop ought to look something like this:
findfactorial:
jal func_multiply
move $a0,$v0
addi $a1, $a1, -1
bne $a1, $zero, findfactorial
This way you first multiply 4 by 3, then 12 by 2, etc.
There are some other isues in your code. For example, if you jump to FailT you don't immediately exit the program after printing the message - you just keep executing the code after PassT.
Also I'm not sure what this is supposed to do:
factorialDone:
addi $v0, $v0, 1
syscall
If you wanted to execute syscall 1 (print_int), then this is incorrect because it doesn't set up $v0 properly (it should be li $v0,1). And if you wanted this to print the result of your factorial computation then that's not going to happen, because you have a jr $ra right before that, so the only time you end up at factorialDone is if number1 contained 0. Also, you'd have to set up $a0 with the value you want to print.
I'm trying to finish up this MIPS calculator, super basic, my first mips program. It doesn't have to handle overflow or anything like that, just has to work on small, positive numbers.
I've not checked my algorithms for multiply and divide, because I am just trying to get add working.
I cannot for the life of me figure out why the ints will not read in and also I'm getting a memory out of bounds when I call lb $a0, op to display the operator for output and don't understand why.
I'm new to this so anything is probably helpful. Thanks in advance.
.data
# const string for welcome
welc: .asciiz "Welcome to SPIM Calculator 1.0!\n"
p_int: .asciiz "\nPlease give an integer: "
p_op: .asciiz "\nPlease give an operator: "
i_err: .asciiz "\nInput Incorrect, bad operator!\n"
again_str: .asciiz "Another calculation? (y/n)"
rmndr: .asciiz " r: "
new_line: .asciiz "\n"
int1: .word 1 # space to hold int 1
int2: .word 1 # space to hold int 2
raw_in: .space 1 # space to hold raw input
op: .space 1 # space to hold operator char
a_char: .space 1 # space to hold again char
out: .word 1 # space to hold output
remain: .word 1 # space to hold remainder
#operator constants
c_plus: .ascii "+" # const for +
c_min: .asciiz "-" # const for -
c_mult: .asciiz "*" # const for *
c_divi: .asciiz "/" # const for /
c_eq: .asciiz "=" # const for =
c_no: .asciiz "n" # const for n
.text
.globl main
main: li $v0, 4 # syscall 4, print string
la $a0, welc # give argument: string
syscall # actually print string
calc: la $t6, remain # load remainder variable
move $t6, $zero # store 0 in remainder (reset)
li $v0, 4 # syscall 4, print string
la $a0, p_int # give argument: string
syscall # actually print string
li $v0, 5 # tell syscall we want to read int 1
syscall # actually read in int 1
la $s1, int1 # load int1 into $s1
move $s1, $v0 # copy the integer from $v0 to int1
li $v0, 4 # syscall 4, print string
la $a0, p_int # give argument: string
syscall # actually print string
li $v0, 5 # tell syscall we want to read int 2
syscall # actually read in int 2
la $s2, int2 # give $s2 the address to hold int 2
move $s2, $v0 # copy the integer from $v0 to $s2
li $v0, 4 # syscall 4, print string
la $a0, p_op # give argument: string
syscall # actually print string
li $v0, 8 # tell syscall we want to read operator
la $a0, op # give $a0 the address to hold the operator
syscall # actually read in operator
lb $t0, op # load the first byte of op
li $t1, '+' # load const for plus
li $t2, '-' # load const for minus
li $t3, '*' # load const for multiplying
li $t4, '/' # load const for dividing
la $s0, out # load out to $s0
beq $t0, $t1, plus # we're adding
beq $t0, $t2, minus # we're subtracting
beq $t0, $t3, multi # we're multiplying
beq $t0, $t4, divi # we're dividing
# else
j error # incorrect input
plus: add $s0, $s1, $s2 # add our ints, store in $t0
j print
minus: sub $s0, $s1, $s2 # subtract our ints, store in $t0
j print
multi: slt $t1, $t2, $s2 # if our counter is less than int2, set $t1 to 1
beq $t1, $zero, print # if we've reached int2, we're done
add $s0, $s1, $s1 # add int1 and int1, store in out
j multi # loop
divi: la $t0 remain # load remainder into $t0
move $t0, $s1 # set remainder to dividend
add $s0, $zero, $zero # set out to 0, just in case
loop: slt $t1, $t0, $s2 # if remainder is less than divisor, set 1
beq $t1, $zero, print # if we're done branch to done
sub $t0, $t0, $s2 # sub divisor from remainder, store in remainder
addi $s0, $s0, 1 # increment quotient by 1
j loop # loop
print: li $v0, 1 # tell syscall we want to print int
la $a0, int1 # give syscall int1 to print
syscall # actually print int
li $v0, 4 # tell syscall we want to print string
lb $a0, op # tell syscall we want to print operator
syscall # actually print string
li $v0, 1 # tell syscall we want to print int
la $a0, int2 # give syscall int2 to print
syscall # actually print int
li $v0, 4 # tell syscall we want to print string
la $a0, c_eq # tell syscall we want to print operator
syscall # actually print string
li $v0, 1 # tell syscall we want to print integer
la $a0, out # give syscall our output
syscall # actually print int
la $t0, remain # load remainder
beq $t0, $zero, again # if we have no remainder, finish printing
li $v0, 4 # tell syscall we want to print string
la $a0, rmndr # tell syscall we want to print remainder string
syscall # print "r: "
li $v0, 1 # tell syscall we want to print int
la $a0, remain # give syscall our remainder to print
syscall # print remainder
again: li $v0, 4 # tell syscall we want to print string
la $a0, new_line # tell syscall to print new line
syscall
la $a0, again_str # load prompt for again string for syscall
syscall
li $v0, 8 # tell syscall we want to read string
la $a0, a_char # tell syscall to put it in $a0
syscall
lb $t0, a_char
li $t1, 'n' # get n char so we can compare
beq $t0, $t1, exit # if we are done, exit
#else loop
j calc # jump to beginning
error: li $v0, 4 # tell syscall we want to print string
la $a0, i_err # give syscall what to print
syscall # actually print
j again # go to prompt for retry
exit: li $v0, 10 # exit code
syscall #exit!
screenshot
The problem is that you don't use the appropriate instruction to handle memory.
Instead of move you should use sw (store word). This code will not store the int into int1:
la $s1, int1 # load int1 into $s1
move $s1, $v0 # copy the integer from $v0 to int1
instead, you should write:
la $s1, int1 # load address of int1 into $s1
sw $v0, 0($s1) # copy the integer from $v0 to int1
Like storing, loading from memory require two instructions:
la $s1, p_op # or whatever register you choose to use
lb $a0, 0($s1) # load byte from the address stored in $s0 (in index 0)
if you want to load the address of p_op into $a0, you should use la $a0, p_op, not lb