The question is:
Assume that the base address of the arrays A and B are in registers $s6 and $s7, respectively.
And the variables f and g are assigned to registers $s0, $s1, respectively.
What is the corresponding MIPS assembly code for the following C code: f = g - A[B[4]];
My idea is:
lw $t0, 16($s7) # $t0 = B[4]
lw $t1, 64($s6) # $t1 = A[B[4]]
sub $s0, $s1, $t1 # $s0 = $s1 - $t1
I got wrong on this answer and I don't know why. Can someone help me on an idea or explanation, please?
Good attempt, but your code can't be right because $t0 was loaded but never used. I'm also not sure where the number 64 came from, but basically that should be the value pulled from B[4], $t0.
You might be confused by the nested array access A[B[4]]. Conceptually, this is using the value stored in B[4] as an index into A. It's better to expand that out and start with the single-operation-per-line C code:
t0 = B[4];
t1 = A[t0];
f = g - t1;
Now it's easier to come up with:
lw $t0, 16($s7) # B_val = B[4]
sll $t0, $t0, 2 # B_val *= 4
addu $t2, $t0, $s6 # A_offset = B_val + A_base
lw $t1, ($t2) # A_val = A[A_offset]
sub $s0, $s1, $t1 # f = g - A_val
Here, I assume the B value needs to be multiplied by 4.
You can always write a program to validate your work (at least, after the exam):
.data
A: .word 1, 1, 1, 1, 24
B: .word 1, 1, 1, 1, 4
.text
main:
la $s6 A # A_base
la $s7 B # B_base
li $s1, 42 # g = 42
lw $t0, 16($s7) # B_val = B[4]
sll $t0, $t0, 2 # B_val *= 4
addu $t2, $t0, $s6 # A_offset = B_val + A_base
lw $t1, ($t2) # A_val = A[A_offset]
sub $s0, $s1, $t1 # f = g - A_val
li $v0, 1
move $a0, $s0
syscall # => should be 42 - 24 = 18
li $v0, 10
syscall
Related
Assume that the variables f and g are assigned to registers $s0, $s1. Assume that the base address of the arrays A and B are in registers $s6 and $s7 respectively. Below is the MIPS code I have written to translate A[2*(f+g)] = B[B[16 + f/2] ]:
# accessing the correct address for A[2*(f+g)]
line 1. add $t0, $s0, $s1 # $t0 = f + g
line 2. add $s6, $s6, $t0 # A[0] should update to A[(f+g)/4]
line 3. sll $s6, $s6, 3 # A[(f+g)/4] should update to A[(8*((f+g)/4)]
line 4. srl $s0, $s0, 1 # f = f/2
line 5. addi $s0, $s0, 16 # f = f/2 + 16
line 6. sll $s0, $s0, 2 # f = (f/2 + 16) * 4
line 7. add $s7, $s0, $s7 # B[0] should update to B[f/2 + 16]
line 8. sll $s7, $s7, 2 # B[f/2 + 16] should update to (B[f/2 + 16]) * 4
line 9. add $t0, $s7, $0 # $t0 = (B[f/2 + 16]) * 4
line 10. sw $s6, $t0($s7) # should be storing B[(B[f/2 + 16]) * 4] in A[2*(f+g)]
I think that I am messing up with access the memory location inside of array B when you need to access it twice. Can someone help?
I believe the correct solution is the following:
add $t0, $s0, $s1
sll $t0, $t0, 3
add $s6, $t0, $s6
srl $t1, $s0, 1
addi $t1, $t1, 16
sll $t1, $t1, 2
add $t2, $s7, $t1
lw $t3, 0($t2)
add t4, $s7, $t3
lw $t5, 0($t4)
sw $t5, 0($s6)
i'm doing an assignment now, it's almost done but i keep getting error saying
Unaligned address in inst/data fetch: 0x10010016
at line:
lw $t3,0($a1) # get the value of b[k] and save it into t3
I search online and i find an answer saying i have to use .align 2 to fix this, but that doesn't work for my problem.
can someone please give me a hint on this, I literally spend 6 hours on this..
thank you very much
Here is my code:
# a -> $a0
# b -> $a1
# n -> $a2
# j -> $a3
# k -> $s0
# i -> $t0
.data
.align 2
arra: .word 1,2,7,4,5
arrb: .word 3,4,7,2,9
.text
la $a0, arra # we have array a[] = { 1,2,7,4,5}
la $a1, arrb # we have array b[] = {3,4,7,2,9}
addi $a2,$zero,0 # n = 0
addi $a2,$zero,3 # n = 3
addi $a3,$zero,0 # j = 0
addi $a3,$zero,3 # j = 3
addi $s0,$zero,0 # k = 0
addi $s0,$zero,2 # k = 2
g:
addi $sp, $sp, -24
sw $ra, 20($sp) # save $ra on stack
sw $s0, 16($sp) # save $s0 (k) on stack
sw $a0, 12($sp) # save a0(a) on stack
sw $a1, 8($sp) # save a1(b) on stack
sw $a2, 4($sp) # save a2(n) on stack
sw $a3, 0($sp) # save a3(j) on stack
move $a3,$s0 # set j = k
jal f # f(a,b,n,k,k)
add $a1,$a1,$s0 # return the address of b[k]
lw $t3,0($a1) # get the value of b[k] and save it into t3
add $v0, $t3,$zero # return the value
lw $a3,0($sp)
lw $a2,4($sp)
lw $a1,8($sp)
lw $a0,12($sp)
lw $s0,16($sp)
lw $ra,20($sp)
addi $sp,$sp,24
jr $ra
f:
bne $a2, $zero, ELSE # if (n != 0) go to ELSE
addi $t0, $zero, 1 # set $t0 = 1
sw $t0, 0($a1) # then set b[0] = 1
addi $t0, $zero, 1 # set $t0 = 1
sw $t0, 0($a1) # then set b[0] = 1
addi $t0, $zero, 1 # set i = 1 for the loop
forLoop:
slt $t1,$s0, $t0 # if k < i, end the loop, use $t1 to store the boolean value
bne $t1, 1, forLoopDone
add $a1, $a1, $t0 # b[i] address
add $t2,$zero,$zero
sw $t2, 0($a1) # b[i] = 0
addi $t0, $t0, 1 # i = i + 1
j forLoop
ELSE:
bne $a3, $zero, updateJ # test if (j == 0), if not, j = j -1
j iteratef
updateJ:
addi $a3, $a3, -1 # j = j -1
j iteratef
iteratef:
addi $a2, $a2, -1 # iterate, n = n - 1
j f # f(b, a, n-1, j_update, k)
bne $a3, $zero, forLoop1Ini # if (j != 0), go to for_loop1_ini
lw $a0, 0($a0) # there might be sth wrong here
sw $a1, 0($a1) # set b[0] = a[0]
addi $a3, $a3, 1 # j++
forLoop1Ini:
addi $t0, $a3, 0 # set i = j
forLoop1Start:
slt $t1,$s0, $t0
bne $t1, 1, forLoop1Done
add $a0, $a0, $t0 # get a[i] address
lw $t1, 0($a0) # t1 = a[i]
lw $t2, -4($a0) # get b[i]
add $a1, $a1, $t0 # get b[i] address
add $t1, $t1, $t2 # t1 = a[i-1] + a[i]
sw $t1, 0($t1) # b[i] = a[i-1] + a[i]
addi $t0, $t0, 1 # i++
j forLoop1Start
forLoop1Done:
nop
forLoopDone:
nop
jr $ra
Your problem is that you are not taking into account the size of each element of the array. Each element occupies 4 bytes.
Therefore, instead of issuing
add $a1,$a1,$s0 # return the address of b[k]
you should multiply the index by 4 (which is the size of element) to get the effective offset:
sll $s1, $s0, 2 # Compute effective offset (i.e. multiply index by 4)
add $a1,$a1,$s1 # return the address of b[k]
lw $t3,0($a1) # get the value of b[k] and save it into t3
I stuck on this problem. I am given a C code and I need to convert it to MIPS.
Here is the C code:
for (c = 0; c < a; c++)
for (d = 0; d < b; d++)
D[8*d] = c + d;
assume the values of a, b, c, d are in the registers $s0, $s1, $t0, and $t1. Also the register $s2 contains the base address of array D.
Here is my following MIPS code so far:
add $t0, $zero, $zero # initialize c = 0
LOOP1: slt $t2, $t0, $s0 # temp reg $t2 = 1 if $t0 < $s0
beq $t2, $zero, DONE # if $t2 = 0, go to DONE
add $t1, $zero, $zero #initialize d = 0
LOOP2: slt $t3, $t1, $s1 # temp reg $t3 = 0 if $t1 < $s1
beq $t3, $zero, L1 # if $t3 = 0, jump to L1 (current iteration of
#LOOP1)
sll $t1, $t1, 3 # $t1 = $t1 << 8 where (8 * d)
????
addi $t1, $t1, 1 # increment d = d + 1
j LOOP2 # jump back to LOOP2
L1: addi $t0, $t0, 1 # increment c = c + 1
J LOOP1 # jump back to LOOP1
DONE:
Where I'm stuck is in the "????" because I dont know how to store $t1 containing 8*d, back into $s2.
Thanks
One problem is that you overwrite the value that's in d every time through LOOP2 - with the statement sll $t1, $t1, 3 you're saying 'replace d with d * 8'. You should store that in another temp register so you don't clobber your loop counter - ie. sll $t4, $t1, 3.
Next you need to figure out what the address D[8 * d] is. Since you already have 8 * d stored in register $t4, it's just a matter of adding those two registers together - add $t5, $s2, $t4. Now, $t5 contains the address you need to store into.
The only things left are computing the value and storing it - to compute it is simple, it's just c + d so all you need is to store that in another temp register - add $t6, $t0, $t1.
Now, $t6 contains the value, and $t5 the address. You just need to store $t6 into $t5 - sw $t6, ($t5).
I am having an issue with the following code I am using for an assignment.. Note, I do not want anybody just giving me code, I am really trying to understand MIPS. I am using the QTSpim simulator to run my MIPS code.
The following code is supposed to allow the user to enter 10 integers from the keyboard, then take those integers and sum the ones that are less than the first inputted integer (ie. 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 would sum all numbers except 10, to equal 45). Then, the program should output the array in the order it was given. Currently, my code is allowing the user to enter 10 integers, but then funny things happen. It sums the numbers in a way that I cannot follow (the most common sums somehow being 0, 4, and 50), and will then only print out 4 integers for the array list (which seems to be as follows: firstNumber, secondNumber, lastNumber, 10) I am really confused as to why this happens. Also, for some instances of integers, it will create an infinite loop outputting 0.
I've been at this for hours, can somebody please give me some advice or pointers?
All help is appreciated. Thanks!
# DATA DECLARATION
.data
request: .asciiz "Enter an integer:\n"
sumLine: .asciiz "The sum is: "
aList: .asciiz "The array contains the following: \n"
return: .asciiz "\n"
array: .word 0
aLength: .word 10
input: .word 0
count: .word 0
count2: .word 0
count3: .word 0
sum: .word 0
next: .word 0
first: .word 0
one: .word 1
# PROGRAM CODE
.text
.globl main
# PROGRAM EXECUTION
#--------------------------------------------------------------------------
# Procedure main
# Description: Initializes registers and prints the final sum.
# parameters: $s0 = address of array, $t0 = length
# return value: $v0 = sum
# registers to be used: $s0, $t0, $t1, $t2, $t4, $t5, $v0
#--------------------------------------------------------------------------
main:
la $s0, array # s0 = array
lw $t0, aLength # t0 = aLength
lw $t1, count # t1 = count
lw $t2, input # t2 = input
lw $t3, count2 # t3 = count2
lw $t4, count3 # t4 = count3
lw $t5, sum # t5 = sum
lw $t6, first # t6 = first
lw $t7, next # t7 = next
lw $t9, one # t9 = one
beq $t1, $zero, readArray # if count=0, goto readArray procedure
la $a0, sumLine # load line to print
li $v0, 4 # print sum output line
syscall
lw $a0, sum # load sum to print
li $v0, 1 # print sum
syscall
la $a0, return # load line to print
li $v0, 4 # print return line
syscall
la $a0, aList # load line to print
li $v0, 4 # print the array list line
syscall
j printArray
#--------------------------------------------------------------------------
# Procedure readArray
# Description: Reads integers from the keyboard.
# parameters: $s0 = address of array, $t0 = length
# return value: --------
# registers to be used: $v0, $a0, $t0, $t1, $t2, $s0
#--------------------------------------------------------------------------
readArray:
beq $t1, $t0, sumSmallerThanFirst # if t1=t0 (count = aLength) goto sum procedure
la $a0, request # load line to print
li $v0, 4 # print request line
syscall
li $v0, 5 # read integer from keyboard
syscall
sw $v0, input # store integer to input
lw $t2, input # t2 = input
sw $t2, 0($s0) # array[i] = t2
addi $s0, $s0, 4 # increment array (i++)
addi $t1, $t1, 1 # increment count (count+1)
sw $t1, count # store count to t1
beq $t1, $t9, store # if t1=t9 (count = one) goto store
j readArray
store:
lw $t6, 0($s0) # t6 = array[i]
sw $t6, first # t6 = first
j readArray
#--------------------------------------------------------------------------
# Procedure sumSmallerThanFirst
# Description: Sums the inputted integers if they are < the first integer.
# parameters: $s0 = address of array, $t0 = length
# return value: ----------
# registers to be used: $s0, $t0, $t3, $t5, $t6, $t7, $t8, $0
#--------------------------------------------------------------------------
sumSmallerThanFirst:
la $s0, array
beq $t3, $t0, main # if count=length, goto main
lw $t7, 0($s0) # t7 = array[i]
sw $t7, next # t7 = next
slt $t8, $t7, $t6 # if t7<t6, t8=1
addi $s0, $s0, 4 # array[i++]
addi $t3, $t3, 1 # count+1
sw $t3, count2 # store count2 to t3
beq $t8, $zero, sumSmallerThanFirst # if t8=0, goto top sum
add $t5, $t5, $t7 # t5=t5+t6 (sum = sum + array[i])
sw $t5, sum # store sum to t5
j sumSmallerThanFirst
#--------------------------------------------------------------------------
# Procedure printArray
# Description: Prints out the array of inputted integers.
# parameters: $s0 = address of array, $t0 = length
# return value: -------------
# registers to be used: $v0, $t0, $t4, $t6, $s0
#--------------------------------------------------------------------------
printArray:
beq $t4, $t0, Exit # if count=length, goto Exit
lw $t7, 0($s0) # t7 = array[i]
sw $t7, next # t7 = next
lw $a0, next # load array[i] to print
li $v0, 1 # print array[i]
syscall
la $a0, return # load line to print
li $v0, 4 # print return line
syscall
addi $s0, $s0, 4 # array[i++]
addi $t4, $t4, 1 # count+1
sw $t4, count3 # store count3 to t4
j printArray
Exit:
jr $ra # return
in the same position as you on what i think is the exact same assignment.
regarding the array....
if you defined array as space it'll give you some weird issues... If you define it as word. You won't have such problem. I guess this is because of the difference alignment for space and word in the kernel because I did notice the different operation in the kernel level.
however... regarding the sum.... i keep getting ridiculous answers, mainly either 0, 1, or -1.
Trying to convert this c code into MIPS and run it in SPIM.
int A[100], B[100];
for(i=1; i<100; 1++){
A[i] = A[i-1] + B[i];
}
So far this is what I have.
# comments are delimted by has marks
.data
A: .word 0:100 # array of 12 integers
B: .word 0:100 # array of 12 integers
.text
main:
li $v0, 1 # load the value "1" into register $v0
li $t0, 1 # load the value "1" into register $t0
li $t1, 100 # load the value "100" into register $t1
blt $t0, $t1, loop # branches to Loop if $t0 < 100
la $t9, B
la $t8, A
loop:
sll $t0, $t0, 2
add $t2, $t9, $t0
lw $s4, 0($t9)
add $t3, $t0, -1
add $t4, $t8, $t3
lw $s5, 0($t4)
add $t5, $t2, $s5
add $t6, $s0, $t0
sw $t7, 0($t5)
addi $t0, $t0, 1
li $v0, 1 # system call for print_int
move $a0, $t0 # the sum to print
syscall # print the sum
When running in SPIM I get the following errors:
Exception occurred at PC=0x00400040
Bad address in data/stack read: 0x00000004
Exception occurred at PC=0x0040004c
Unaligned address in inst/data fetch: 0x00000003
Exception occurred at PC=0x00400058
Bad address in data/stack read: 0x00000000
Attempt to execute non-instruction at 0x0040006c
Some direction would be nice. Thanks
You are branching to loop (blt $t0, $t1, loop) before you initialize the pointers to A and B. You need to move the blt $t0, $t1, loop to the end of your code, not have it at the beginning.
I hate to do this, but there are too many things wrong to list them all. Try this:
.data
A: .word 0:100 # array of 100 integers
B: .word 0:100 # array of 100 integers
.text
main:
li $t0, 4 # load the value "1" into register $t0
li $t1, 400 # load the value "100" into register $t1
la $t9, B
la $t8, A
loop:
add $t2, $t9, $t0 # $t2 = B + i
lw $s4, 0($t9) # $s4 = B[i]
add $t3, $t0, -4 # $t3 = i - 1
add $t4, $t8, $t3 # $t4 = A + i - 1
lw $s5, 0($t4) # $s5 = A[i - 1]
add $t5, $t8, $t0 # $t5 = A + i
add $t6, $s4, $s5 # $t6 = B[i] + A[i - 1]
sw $t6, 0($t5) # A[i] = $t6
addi $t0, $t0, 4 # i++
li $v0, 1 # system call for print_int
move $a0, $t6 # the sum to print
syscall # print the sum
blt $t0, $t1, loop # branches to Loop if $t0 < 100
Right off the bat, s1 and s2 should be initialized to the stack-based (I assume) address of your arrays.