Related
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
I was given the following C code to implement in MIPS assembly.
for(i=0; i<16, i++){
for(i=0; j<16, j++){
C[i][j] = A[i][j] = B[j][i]
}
}
The arrays are already initialized for us, we only have to deal with the memory.
Here's how i made my nested loop.
First:
bge $t1, $t0, Exit
Second:
bge $t2, $t0, Continue
#do work here.
addi $t2, $t2, 1
j Second
Continue:
addi $t1, $t1, 1
j First
Exit:
Loading the counters:
addi $t0, $t0, 16
move $t1, $zero
move $t2, $zero
la $t3, A
la $t4, B
la $t5, C
And logic for A[i][j] using the formula Base + Word Length * (Row * Max size + Col):
sllv $t6, $t0, $t1 #Row, shift 16 by current counter -> 32 -> 64..
addu $t6, $t6, $t2 #Column, add column counter.
sll $t6, $t6, 2 #Shift entire count by word length.
addu $t6, $t6, $t3 #Add A base address.
lw $t7, ($t6) #Load word from that address.
Full code:
addi $t0, $t0, 16
move $t1, $zero
move $t2, $zero
la $t3, A
la $t4, B
la $t5, C
First:
bge $t1, $t0, Exit
Second:
bge $t2, $t0, Continue
###
#Zero out counters first.
move $t6, $zero
move $t7, $zero
move $t8, $zero
move $t9, $zero
sllv $t6, $t0, $t1 #Row, shift 16 by current counter -> 32 -> 64..
addu $t6, $t6, $t2 #Column, add column counter.
sll $t6, $t6, 2 #Shift entire count by word length.
addu $t6, $t6, $t3 #Add A base address.
lw $t7, ($t6) #Load word from that address.
sllv $t7, $t0, $t2 #Row, shift 16 by current counter -> 32 -> 64..
addu $t7, $t7, $t1 #Column, add column counter.
sll $t7, $t7, 2 #Shift entire count by word length.
addu $t7, $t7, $t4 #Add B base address.
lw $t8, ($t7) #Load word from that address.
addu $t9, $t7, $t8 #add A and B results.
addu $t7, $t6, $t5 #add C base address, reuses $t7, copies $t6 from *A* array.
sw $t9, 0($t7) #store above result to C.
###
addi $t2, $t2, 1
j Second
Continue:
addi $t1, $t1, 1
j First
Exit:
I'm getting a bad address error but I can't seem to figure out what is wrong.
There are at least three errors:
You are overwriting $t6 which should have the offset of A and C with the base address of A
You are overwriting $t7 which should hold the content of A[i][j] with the address of B[j][i]
You are miscalculating the row offset. Instead of shifting 16 row times, you should shift row 4 times (which effectively multiplies row by 16)
You may change
sllv $t6, $t0, $t1 #Row, shift 16 by current counter -> 32 -> 64..
...
addu $t6, $t6, $t3 #Add A base address.
lw $t7, ($t6) #Load word from that address.
...
sllv $t7, $t0, $t2 #Row, shift 16 by current counter -> 32 -> 64..
...
addu $t9, $t7, $t8 #add A and B results
with
sll $t6, $t1, 4 # Row
...
addu $t7, $t6, $t3 #Add A base address.
lw $t9, ($t7) #Load word from that address.
...
sll $t7, $t2, 4 # Row
...
addu $t9, $t9, $t8 #add A and B results.
Down below is my code from a MIPS hw assignment where we have to multiply two matrixes. Our task was to implement the matrix_multiply function and matrix_print function
.data
matrix_a: .word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
matrix_b: .word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
result: .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
newline: .asciiz "\n"
tab: .asciiz "\t"
#############################################################################
#############################################################################
## Text segment
#############################################################################
#############################################################################
.text # this is program code
.align 2 # instructions must be on word boundaries
.globl main # main is a global label
.globl multiply
.globl matrix_multiply
.globl matrix_print
.globl matrix_ask
#############################################################################
matrix_ask:
#############################################################################
# Ask the user for the current matrix residing in the $a0 register
sub $sp, $sp, 4
sw $ra, 0($sp)
# init our counter
li $t0, 0
# t1 holds our the address of our matrix
move $t1, $a0
ma_head:
# if counter less than 16, go to ma_body
# else go to exit
li $t2, 16
blt $t0, $t2, ma_body
j ma_exit
ma_body:
# read int
li $v0, 5
syscall
li $t2, 4
# ints are 4 bytes
multu $t0, $t2
mflo $t2
add $t2, $t2, $t1
sw $v0, 0($t2)
j ma_latch
ma_latch:
addi $t0, $t0, 1
j ma_head
ma_exit:
lw $ra, 0($sp)
add $sp, $sp, 4
jr $ra
#############################################################################
main:
#############################################################################
# alloc stack and store $ra
sub $sp, $sp, 4
sw $ra, 0($sp)
# load A, B, and result into arg regs
la $a0, matrix_a
jal matrix_ask
la $a0, matrix_b
jal matrix_ask
la $a0, matrix_a
la $a1, matrix_b
la $a2, result
jal matrix_multiply
la $a0, result
jal matrix_print
# restore $ra, free stack and return
lw $ra, 0($sp)
add $sp, $sp, 4
jr $ra
##############################################################################
multiply:
##############################################################################
# mult subroutine $a0 times $a1 and returns in $v0
# start with $t0 = 0
add $t0,$zero,$zero
mult_loop:
# loop on a1
beq $a1,$zero,mult_eol
add $t0,$t0,$a0
sub $a1,$a1,1
j mult_loop
mult_eol:
# put the result in $v0
add $v0,$t0,$zero
jr $ra
##############################################################################
matrix_multiply:
##############################################################################
# mult matrices A and B together of square size N and store in result.
# alloc stack and store regs
sub $sp, $sp, 24
sw $ra, 0($sp)
sw $a0, 4($sp)
sw $a1, 8($sp)
sw $s0, 12($sp)
sw $s1, 16($sp)
sw $s2, 20($sp)
add $t5, $zero, $zero #Set t5 to zero. i = 0
add $t6, $zero, $zero #Set t6 to zero. j = 0
add $t7, $zero, $zero #Set t7 to zero. k = 0
#setup for i loop
iLoop:
beq $t5, 4, exit
j jLoop
#setup for j loop
jLoop:
beq $t6, 4, iEnd
#setup for k loop
kLoop:
beq $t7, 4, jEnd
# compute A[i][k] address and load into $t3
# A[i][k] = A+4*((4*i) + k)
sll $t3, $t5, 2 # Store 4*i in $t3
addu $t3, $t3, $t7 # Adds $t3 to k
sll $t8, $t3, 2 # Computes 4*($t3) = 4*(4*i+k) by temporarily storing the product in $t8
move $t3, $t8 # Stores 4*($t3) into $t3
addu $t3, $t3, $a0 # Adds A to $t3
lw $t3 0($t3)
# compute B[k][j] address and load into $t4
# B[k][j] = B+4*((4*k) + j)
sll $t4, $t7, 2 # Stores 4*k in $t3
addu $t4, $t4, $t6 # Adds $t4 to j
sll $t8, $t4, 2 # Computes 4*($t4) = 4*(4*k+j) by temporarily storing the product in $t8
move $t4, $t8 # Stores 4*($t4) into $t4
addu $t4, $t4, $a1 # Adds B to $t4
lw $t4 0($t4)
# call the multiply function
multu $t3, $t4
mflo $t9
# compute RESULT[i][j] address and load into $t1
# RESULT[i][j] = RESULT+4*((4*i) + j)
sll $t1, $t5, 2 # Store 4*i in $t1
addu $t1, $t1, $t6 # Adds $t1 to j
sll $t8, $t1, 2 # Computes 4*($t1) = 4*(4*i+k) by temporarily storing the product in $t8
move $t1, $t8 # Stores 4*($t1) into $t1
addu $t1, $t1, $a2 # Adds A to $t3
lw $t1 0($t1)
sw $a2 0($t9) # Store $t9 into its respective location in $a2
# increment k and jump back or exit
addi $t7, $t7, 1
j kLoop
jEnd:
#increment j and jump back or exit
addi $t6, $t6, 1
li $t7, 0
j jLoop
iEnd:
#increment i and jump back or exit
addi $t5, $t5, 1
li $t6, 0
j iLoop
exit:
# retore saved regs from stack
lw $s2, 20($sp)
lw $s1, 16($sp)
lw $s0, 12($sp)
lw $a1, 8($sp)
lw $a0, 4($sp)
lw $ra, 0($sp)
# free stack and return
add $sp, $sp, 24
jr $ra
##############################################################################
matrix_print:
##############################################################################
# alloc stack and store regs.
sub $sp, $sp, 16
sw $ra, 0($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $a0, 12($sp)
li $t0, 4 # size of array
# do your two loops here
# setup to jump back and return
lw $ra, 0($sp)
lw $s0, 4($sp)
lw $s1, 8($sp)
lw $a0, 12($sp)
add $sp, $sp, 16
jr $ra
I keep getting one of the two following errors - Either I get an error saying Exception occurred at PC=0x004000cc, Arithmetic overflow or "The Following Symbols are Undefined" and it lists iEnd, matrix_print, exit, and jEnd. I don't know why those symbols would be "undefined since they're clearly written in my code, and they don't have to be "global" symbols, otherwise matrix_print wouldn't have been included in that list.
I realize I haven't yet implemented my matrix_print, but I'll get to that once I figure out what's causing the more pressing issue, which is my Arithmetic Overflow error. I use sll knowing I need to multiply by 4, and sll is the best way to approach it. I don't believe I'm going out of bounds anywhere either, so if someone can please help me debug this I would greatly appreciate it. Thanks!
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
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.