MIPS Printing Mathematical Equations - mips

I was just starting off with MIPS and solving a few mathematical problems i had in class using MIPS and i was trying a new concept and couldn't understand how to print answer using the same variables we use for storing values and not take an extra variable just for storing the answers and an example question was (b^2 + ac)/a.

So the solution is quite simple and you can easily do this by following my solution.
.text
.globl main
main :
li $t0 , 3 #storing a
li $t1 , 1 #storing b
li $t2 , 4 #storing c
mul $t1 , $t1 , $t1 # b^2
mul $t2 , $t2 , $t0
add $t1 , $t1 , $t2 # b^2 + ac
div $t1 , $t1 , $t0 # (b^2 + ac)/a
end :
li $v0 , 10
syscall

to print any value in a register in any format you want just follow the syscall table in this link enter link description here
for example if you want to print the number 5 you do the following:
li $v0, 1 # code 1 prints integer according to the syscall table
li $a0, 5 # load desired value into argument register $a0
syscall # execute given value in a0 and format in v0
the print value MUST be in a0. you can temporarily save a0 in different register in case you dont want to lose its original value.

Related

Why I have the error "store address not aligned on word boundary"

I have a problem with my MIPS code... I would check the occurrences in a string passed by keyboard without a character to compare. I have the string in the stack (stack -255 position) and an array in the .data section to store the occurrences. The basic idea is that I load a letter from the stack one-by-one with a loop (lb $t1, ($a0) t1= ascii code of the letter - a0= stack passed at the function), subtract the letters read from the stack with 97 (97=a) and obtain the index of the array and with another loop, count the occurrences and save this under the index calculated before. Obviously, the array has 104 position (26 letters * 4 because I would save the number of occurrences). The problem is that when I find the index of my array position and I would save inside the position the occurrences with sw $--, myArray($--) Mars give me this error:
Runtime exception at 0x0040007c: store address not aligned on word boundary 0x10010087
I have tried to add .align in the .data section but I haven't find solution, maybe I wrong some things... Any help?
This is my code:
analizza_stringa: (function)
while_string:
# load a byte from the stack
lb $t0, ($a0)
#check end string
beq $t0, $zero, end
#check a line feed
beq $t0, 10, end
#array index
subi $t3, $t0, 97
#Multiply by 4 (I would save number)
mul $t4, $t3, 4
while_occorrenza:
#like before
beq $t1, 10, continue
#load a letter like before
lb $t1,($a0)
#Check the occurrences
bne $t1, $t0, continue2
#add 1 at the occurrences
addi $t5, $t5, 1
continue2:
#add 1 for the pointer at the string
addi $a0, $a0, 1
#Repeat
j while_occorrenza
continue:
#Save the number under the index calculated before
sw $t5, myArray($t4)
#counter=0 for another loop
li $t3, 0
#next character
addi $a0, $a0, 1
# repeat the first loop
j while_string
end:
jr $ra
If you want to access a word in memory, the address must be word-aligned (a multiple of 4).
Assuming that $t4 contains a multiple of 4, which it appears to do, that means myArray isn't word-aligned. To fix this you would add .align 2 on the line before myArray in your data section.

Self-Modifying MIPS Code

I'm trying to write a program in MIPS that continuously prompts for two integers and prints the sum until the sum is 0. The trick is that if the sum is 13, I need to call a method to change the assembled MIPS code so that
add $t2, $t0, $t1
becomes
and $t2, $t0, $t1
and all subsequent runs of the loop use the and instruction.
I have the summation loop working so that when 13 is the sum the method instMod is called which I want to modify the instruction. Unfortunately, I have no idea where to start and can't find any examples of this online. I assume I need to somehow get the hex code of the add out of the assembled code and replace it with the hex code for the and but I do not know how to do that or if that is the right course of action to take.
# Nick Gilbert
# MIPS Program to demonstrate self-modifying code
.data
num1Prompt: .asciiz "Enter num1: "
num2Prompt: .asciiz "Enter num2: "
num1: .word 0
num2: .word 0
addOut: .asciiz "ADD: "
andOut: .asciiz "AND: "
.text
main:
sumLoop:
la $a0, num1Prompt #Asking user for num1
li $v0, 4 #Call code to print string
syscall
li $v0, 5 #Call code to read an int
syscall
move $t0, $v0 #Moving read int to $t1
la $a0, num2Prompt #Asking user for num2
li $v0, 4 #Call code to print string
syscall
li $v0, 5 #Call code to read an int
syscall
move $t1, $v0 #Moving read int to $t2
add $t2, $t0, $t1 #Adding num1 and num2 together
la $a0, addOut
li $v0, 4
syscall
move $a0, $t2
li $v0, 1
syscall
beq $t2, 13, instMod #Calling method to modify add instruction if sum = 13
bne $t2, 0, sumLoop #If result is not yet 0, ask for new sum
endSumLoop:
li $v0, 10
syscall
instMod: #Method to change add instruction to an and instruction
Add a label at the instruction you want to replace, e.g:
instruction_to_be_replaced:
add $t2, $t0, $t1 #Adding num1 and num2 together
then in your routine instMod
instMod: #Method to change add instruction to an and instruction
lw $t1, instruction_to_replace
sw $t1, instruction_to_be_replaced
j sumLoop # go back to your sumLooop
instruction_to_replace:
and $t2, $t0, $t1
The code loads in temporary register $t1 the contents of the instruction you want to replace, and then stores it in the location labelled instruction_to_be_replaced.
The "source" of the instruction goes labelled in instruction_to_replace.
To do this, you need to be able to write on the code section which I assume you have otherwise you would not be asking this question.
Try this:
Assemble the instruction that you need to an object file
Extract the hexadecimal of the equivalent machine code
Place a label in front of the code you need to change
mov the hexidecimal from step 2 into the location from step 3 in your instMod section
For this to function the two instructions with operands must be of identical length. If they are not, pad the original or the replacement with nop as appropriate.

how to add +4 in an array address in MIPS

i am trying to use a loop to store say '2' integers to an array. So i thought i will use a loop that goes on 2 times, and each times it store a number in Array1 + cngAdd , where i will initialize cngAdd to 0 at beginning, and increase it by 4 at the end of loop. so at second iteration of loop the address is added by 4.
So to read the input i do:
li $t7, 2
li $t6, 1
intReadStore:
li $v0, 5
syscall
sw $v0, Array1 + cngAdd
lw $t0, cngAdd
li $t0, $t0, 4
sw $t0, cngAdd
li $t6, $t6, 1
ble $t6, $t7, intReadStore
But in qtspim i get an error in this statement : sw $v0, Array1 + cngAdd
Could you please tell what should i use instead of cngAdd (so that i change the address by + 4 , using some variable , or by even using any general purpose integer register, without hardcoding "4")?
Note: my data are:
.data
cngAdd .word 0
Array1 .space 2
my Array1 is of 2 integers here but i want to do it for 'n'. however for this question 2 is sufficient i think.
thanks.
Put the base address in a register, and increase it once per loop iteration:
la $a3,Array1 # Put the address of Array1 in register $a3
intReadStore:
li $v0, 5
syscall
sw $v0, ($a3) # Store the value at the currently pointed to element of Array1
addiu $a3,$a3,4 # Point to the next word in Array1
You may need to save/restore $a3 when you do the syscall, since the value of $a3 might not be preserved.
By the way, the size argument for .space is in bytes as far as I know. So for 2 words you need to reserve 8 bytes of space.

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.

MIPS: Selective copying from one string to another error

I have tried to write a program in MIPS that takes a string and prints a result with only characters (assuming that the string is alphanumerical). It works perfectly for strings of size < 4, but when a 4th character occurs, it goes into infinite loop.
.data
string: .word 10
.data
result: .word 10
.data
message1: .asciiz "number\n"
.data
message2: .asciiz "letter "
.data
message3: .asciiz "finished loop\n"
.text
main:
li $v0 8 # take input as string
la $a0 string # store it in "string"
la $a1 10 # size of "string" is at most 10
syscall
la $s0 string # save address of "string" to s0
la $s1 result # save address of "result" to s1
Loop:
li $t0 10 # set t0 as '/n'
lb $t1 ($s0) # load character that we are currently checking
beq $t0 $t1 Exit # check if we are at the end of the string
li $t0 64 # set t0 to 64 to check if it is a letter (character that we are now checking must be greater than 64)
slt $t2 $t0 $t1 # t2 will store the result of comparison ($t1 - character)
li $t0 0 # set t0 to 0 to check the result of comparison
beq $t2 $t0 Increment # if 64 > ch, then we must just proceed
li $v0 4
la $a0 message2 # print message that it is a character
syscall
sb $t1 ($s1) # copy this character into our "result"
addi $s1 $s1 1 # increment the address of "result"
Increment:
li $v0 4
la $a0 message1 # print message that it is a number
syscall
addi $s0 $s0 1 # increment the address of "string" to proceed in loop
j Loop
Exit:
li $t0 10
sb $t0 ($s1) # add endline character to "result"
addi $s1 $s1 1
li $t0 0
sb $t0 ($s1) # add null character to "result"
li $v0 4
la $a0 message3 # print message that the loop has finished
syscall
li $v0 4
la $a0 result # print result
syscall
jr $ra
Thanks in advance.
Hard to tell without stepping through myself, but here's an idea: use the power of "i", that is, Immediate mode. That way, you don't have to worry about whether a register value isn't quite what you expected. Also, use the special $zero register instead of loading a register with zero. So change this:
li $t0 64 # set t0 to 64 to check if it is a letter (character that we are now checking must be greater than 64)
slt $t2 $t0 $t1 # t2 will store the result of comparison ($t1 - character)
li $t0 0 # set t0 to 0 to check the result of comparison
beq $t2 $t0 Increment # if 64 > ch, then we must just proceed
to this:
slti $t2, $t1, 'A' # A little different: set $t2 if $t1 < 65 ('A')
bne $t2, $zero Increment # branch if $t1 < 'A'
Maybe by eliminating registers in favor of immediates, you can find the glitch that's causing you to go into a loop.
Also, a couple of other possible glitch sources:
You're looking for '\n' to terminate the string, but I'm not sure you can guarantee that the syscall will add \n if the input is a full 10 characters. Perhaps you should also/instead check for the zero-terminator byte value.
You've defined string and result as 10 words, but you're actually storing bytes in them. That shouldn't be a problem - you've allocated 40 bytes instead of 10. But if you ever go back and change those to byte, be sure to allow for that trailing \0 (and \n).
Sorry I can't be more specific, but hope that points you in the right direction.