i have to write a function to calculate the total income from a csv file but I have no idea how to complete it
totalIncome:
#finds the total income from the file
#arguments: a0 contains the file record pointer array location (0x10040000 in our example) But your code MUST handle any address value
# a1:the number of records in the file
#return value a0:the total income (add up all the record incomes)
#if empty file, return 0 for a0
bnez a1, totalIncome_fileNotEmpty
li a0, 0
ret
totalIncome_fileNotEmpty:
# Start your coding from here!
li a0, 0
#if no student code entered, a0 just returns 0 always :(
# End your coding here!
ret
this is my code:
int arraysum(int a[], int size) {
int ret = 0;
int i;
for (i = 0;i < size;i++) {
ret = ret + a[i];
}
return ret;
}
.section .text
.global arraysum
arraysum:
# a0 = int a[]
# a1 = int size
# t0 = ret
# t1 = i
addi t0, zero, 0 # ret = 0
addi t1, zero, 0 # i = 0
1: # For loop
bge t1, a1, 1f # if i >= size, break
slli t2, t1, 2 # Multiply i by 4 (1 << 2 = 4)
add t2, a0, t2 # Update memory address
lw t2, 0(t2) # Dereference address to get integer
add t0, t0, t2 # Add integer value to ret
addi t1, t1, 1 # Increment the iterator
jal zero, 1b # Jump back to start of loop (1 backwards)
1:
addi a0, t0, 0 # Move t0 (ret) into a0
jalr zero, 0(ra)
can someone help me to check if this is right? and did i miss something?
Related
the following mips code is of printing a number pattern like this: 1 12 123 1234 12345 i cannot find the error in my code.I don't understand what is missing.
main:
li $t0,1
li $t1,6
li $t2,1
li $t3,6
out:
beq $t0, $t1, exit
in:
beq $t2,$t3, exit
move $a0,$t2
li $v0, 1
syscall
addi, $t2, $t2, 1 #counter
j in
lineloop:
addi $t0,$t0,1
li $v0, 4 # print new line
la $a0, newline
syscall
j out
exit:
you have not changed $t2 to 1 in the last loop so that it starts printing from 1 everytime the line changes.
Also in the "in" loop you have not added the last loop instead you wrote exit which will make it leave the outer loop as well so you have to write it like this:
beq $t2,$t3,lineloop
SO the final code looks something like this
main:
li $t0,1
li $t1,6
li $t2,1
li $t3,6
out:
beq $t0, $t1, exit
in:
beq $t2,$t3, lineloop
move $a0,$t2
li $v0, 1
syscall
addi, $t2, $t2, 1 #counter
j in
lineloop:
addi $t0,$t0,1
li $v0, 4 # print new line
la $a0, newline
syscall
li $t2,1 #changes value in $t2 back to 1
j out
exit:
Here's some C code equivalent to what you're working on:
for ( int i = 1; i != 6; i++ ) {
for ( int j = 11; j != 62; j++ ) {
printf ( "%d", j );
}
printf ( "\n" );
}
1 The inner loop should be fully nested within the outer loop — that includes its initialization part. Your assembly code has relocated inner loop initialization out of its proper context, and placed it with the (initialization section of the) outer loop:
for ( int i = 1, int j = 11; ; i != 6; i++ ) {
for ( ; j != 62; j++ ) {
printf ( "%d", j );
}
printf ( "\n" );
}
Without the inner loop's initialization being repeated it won't function equivalent to the above C code. You only need move your li $t2, 1 to the proper location:
#li $t2,1 # improper placement of inner loop initialzation
li $t3,6
out:
beq $t0, $t1, exit
li $t2, 1 # here's where inner loop's initialization belongs
# properly nested within the body of the outer loop
# and immediately preceding the inner loop repeating body
in:
beq $t2,$t3, lineloop
2 In order to change the behavior of the inner loop each iteration, the inner loop should be dependent upon the outer loop's control variable, but you don't have it that way. Without that, it will function independently, yielding 12345 each time (so: 12345 12345 12345 12345 for output). The inner loop should take a dependence on the outer loop's control variable to decide when to stop as follows:
for ( int i = 1; i != 6; i++ ) {
for ( int j = 11; j != i+12; j++ ) {
printf ( "%d", j );
}
printf ( "\n" );
}
So, compute i+1 and use that computation to stop the inner loop.
Let's note that you can remove the li $t3,6 since that isn't actually when to stop the inner loop. Also i+1 needs to be computed for the inner loop to use, and could be done within in the inner loop itself, but it is invariant to the inner loop (i only changes in the outer loop), so that computation can be done inside the body of the outer loop instead of inside the body of the inner loop.
#li $t2,1 # improper placement of inner loop initialzation
#li $t3,6 # wrong termination value & computation location (its not constant)
out:
beq $t0, $t1, exit
li $t2, 1 # here's where inner loop's initialization belongs
# properly nested within the body of the outer loop
addi $t3, $t0, 1 # compute i+1 for the inner loop to use as when to stop
in:
#addi $t3, $t0, 1 # alternate location to compute i+1
# but would (re)compute the same value each time
# so can do this outside the inner loop instead as above
beq $t2,$t3, lineloop
I am trying to figure out what the data hazards for this code would be...
lw $15, 8 # load num (8) into register $15
lw $16, 0 # load sum (0) into register $16
lw $17, array # load array into register $14
lw $14, 2 # load sub value(2) into register $14
while:
beq $15, $zero exitLoop # loop for; while(num>=0) statement
add $16, $16, $15 # sum = sum + num
sub $15, $15, $14 # num = num – 2
j while
exitLoop: sw $16, 12($17) # array[3] = sum; the fourth element in array is set to the sum
Looking for the data hazards; where they occur and why
I am trying to implement a for loop in mips like this:
# {
# int sum = 0;
# for(int x = 0; x < n; x++)
# if ( v[x] > 2 )
# sum += v[x];
# return sum;
# }
I have the loop correctly but I can't get the size of the loop right. The loops functions as intended but it runs one extra time. It should be printing a 31 but it ends up running the loop an extra time and getting a 10 from somewhere then getting a 41 as the end result.
Here is my code:
.eqv SIZE 8
values: .half 6, 5, 1, 9, -2, 3, 8, 2
endl: .asciiz "\n"
endv:
# -------------------------------------------------# text/code section
.text
.globl main
main:
# ------
#TODO: call doSum(values, SIZE)
la $s0, values #&v[0]
la $s7, endv
li $a0, 0 #sum = 0
loop:
lh $t1, ($s0) #v[X]
li $t2, 2 #$t2 = 2
bgt $t1, $t2, sumPlus
j increment #skip over sumPlus if not > 2
sumPlus:
add $a0, $a0, $t1 #sum += v[x]
increment:
add $s0, $s0, 2 #x++
blt $s0, $s7, loop
You have a line feed character and a null terminator (endl: .asciiz "\n") before endv, so you're including them in the array that you're summing from. I don't know much about MIPS, but because \n has the value 10 (dec) and the \0 has the value 0. I assume that they're bytes and this is being run on a machine that is little-endian, so as a signed halfword they're interpreted as 10 (dec).
I think that just moving the endv label to the actual end of the array (just before endl:) will solve this.
I'm very new into coding and we started with MIPS. We were kind of "thrown in to the cold water" and had to implement an algorithm that checks whether the elements of an array are sorted in ascending order. If it is sorted, a 1 is to be stored in $v0, otherwise a 0.
The solution that was given us:
.data
A: .word 1, 2, 3, 4, 5
l: .word 5
.text
main:
la $s0, A #address of A
lw $s1, l
add $t0, $0, $0 #counter for loop
addi $v0, $0, 1
sub $s1, $s1, $v0
for:
beq $t0, $s1, done
sll $t1, $t0, 2 #byte offset
add $t1, $t1, $s0
lw $t1, 0($t1) #$t1 = A[j]
addi $t2, $t0, 1
sll $t2, $t2, 2
add $t2, $t2, $s0
lw $t2, 0($t2) #$t2 = A[j + 1]
sub $t3, $t2, $t1 #$s3 = A[j+1] - A[j]?
slt $t4, $t3, $0
addi $t3, $0, 1
beq $t3, $t4 unsort #A isn’t sorted if A[j+1] - A[j] has a negative value
addi $t0, $t0, 1 #$t0 = $t0 + 1
j for
unsort:
add $v0, $0, $0 #set $v0 if array isn’t sorted
done:
I'm having trouble understanding this code/algorithm. First of all what is an Array and why do we need specifically 5 of them?
But much more important to me is understanding this code/algorithm. So I need someone who is kind enough and explains to me step by step and in simple word :D, how this code works.
Would be very helpful and thanks in advance.
Short answer
Basically, this program iterates over the array A in a loop with loop counter, say i. The index i is initialized with 0 and in every loop iteration incremented by 1 until it reaches l-1, where l is the size/length of the array A. In every iteration the algorithm checks if A[i] < A[i + 1] (i.e. if the i-th and the (i+1)-th element in A are in ascending order and thus are sorted). If so, it continues execution and $v0 remains 1. Otherwise it sets $v0 to 0 and terminates.
Long answer
Arrays and memory
An array is basically an ordered list of data – in this case it is an ordered list of words (a word in MIPS means: 32-bit value, and it consists of 4 bytes, each of which has 8 bits of information). So in this case, every word represents a 32-bit integer.
If we have an array A of length l, the elements are indexed from 0 to l-1. The first element in an array A (notation: A[0]) is saved at a certain address in memory, let's call it addr. The i-th element in A (A[i]) is then saved at the memory address addr + 4*i. This is because memory in MIPS is byte-addressable, i.e., every byte has his own address and because a word consists of 4 bytes, word addresses are offset by 4 (see below).
.data section
A: .word 1, 2, 3, 4, 5
l: .word 5
With that you will realize that you don't have 5 arrays but only one (called A) and it contains the values 1, 2, 3, 4 and 5. Thus, the length is 5 and it is specified in the word l. You could add more values to your array but then you would have to adjust the length because otherwise, strange things will happen (or at least the result will be random). Your data is specified in this .data section and is therefore somewhere stored in your program's memory space.
MIPS assembly
In order to understand the code in the .text section, you have to understand MIPS assembly. If I write about a register, just think about it as a placeholder for a 32-bit value. For example, $0 is the zero register and it always stores a 32-bit 0. Other registers are used to temporarily store values used in your program. The instructions you use are:
la rd, label ("load address")
(rd = address of label; stores the address of the word specified by "label" in the destination register rd)
lw rd, label ("load word")
or
lw rd, offset(rs)
(load data specified by label, or data at address rs+offset into destination register rd)
add rd, rs, rt
(rd = rs + rt; adds source registers rs and rt and stores result in destination register rd)
addi rd, rs, imm ("add immediate")
(rd = rs + imm; adds source register rs and immediate (16-bit constant) value and stores result in destination register rd)
sub rd, rs, rt ("subtract")
(rd = rs - rt; subtracts source register rt from source register rs and stores result in destination register rd)
beq rs, rt, label ("branch if equal")
(if value in rs is equal to value in rt, jump to label)
sll rd, rs, shamt ("shift logic left")
(rd = rs << 2; shift value in rs by two bits the left and store it in rd)
slt rd, rs, rt ("set less than")
(rd = (rs < rt) ? 1 : 0; if the value in rs is smaller than the value in rt, set rd to 32-bit 1, otherwise to 32-bit 0)
j label ("jump")
(jump to label)
.text section
main:
la $s0, A
lw $s1, l
add $t0, $0, $0
addi $v0, $0, 1
sub $s1, $s1, $v0
for:
beq $t0, $s1, done
sll $t1, $t0, 2 #byte offset
add $t1, $t1, $s0
lw $t1, 0($t1) #$t1 = A[j]
addi $t2, $t0, 1
sll $t2, $t2, 2
add $t2, $t2, $s0
lw $t2, 0($t2) #$t2 = A[j + 1]
sub $t3, $t2, $t1 #$s3 = A[j+1] - A[j]?
slt $t4, $t3, $0
addi $t3, $0, 1
beq $t3, $t4 unsort #A isn’t sorted if A[j+1] - A[j] has a negative value
addi $t0, $t0, 1 #$t0 = $t0 + 1
j for
unsort:
add $v0, $0, $0 #set $v0 if array isn’t sorted
done:
This assembly code is equivalent to the pseudocode (if you are not used to pseudocode or to while loops, please look it up in the internet):
s0 <- address of first element in A
s1 <- l
t0 <- 0
v0 <- 1
s1 <- s1-1
while (t0 != s1) do
t1 <- 4 * t0
t1 <- t1 + s0
t1 <- word at address t1
t2 <- t0 + 1
t2 <- 4 * t2
t2 <- t2 + s0
t2 <- word at address t2
t3 <- t2 - t1
if (t3 < 0) then t4 <- 1
else t4 <- 0
t3 <- 1
if (t3 == t4) then
v0 <- 0
return
else t0 <- t0 + 1
Hope, this helped. I think it is quite ambitious to start with assembly code if you haven't coded before. Good luck!
I am trying to write a MIPS program that checks if an input string is a palindrome. I tested the string "HelllleH" and when stepping through the program, I saw that during the first loop of PAL_CHECK t0 = 0 but t1 = 104. Logically, t0 = 0 and t1 = 0 also in the first loop. Can someone tell what's wrong in this program?
# a0 is input
# a1 is current character we are looking at
# a2 is length of string
# t0 is character at beginning of string
# t1 is character at end of string
# v0 stores whether string is palindrome or not (0 for false, 1 for true)
ispalindrome:
addi $a2, $0, 0 # length counter
FIND_LEN:
lbu $a1, 0($a0) # load character into $a1
beq $a1, $0, PAL_CHECK # Break if string is at the end
addi $a2, $a2, 1 # increment counter
addi $a0, $a0, 1 # increment str address
j FIND_LEN
PAL_CHECK:
# Is palindrome if length is less than 2
slti $t0, $a2, 2
bne $t0, $0, RETURN_TRUE
# Check first and last chars to see if they are the same
lbu $t0, 0($a0) # first char is t0
add $t1, $a2, $a0 # last char is t1
lbu $t1, 0($t1)
bne $t0, $t1, RETURN_FALSE # if they are not equal, return false
# continue recursion
addi $a2, $a2, -2
addi $a0, $a0, 1
j PAL_CHECK
RETURN_FALSE:
addi $v0, $0, 0
jr $ra
RETURN_TRUE:
addi $v0, $0, 1
jr $ra
While finding the length of the string you continually increment $a0 to point at the next character, until you find the NUL terminator at the end of the string. You never reset $a0 before the palindrome check loop, so it's still pointing at the NUL terminator when you begin that loop. So you'll actually be comparing data that's past your string.
It would make more sense to implement the check this way (I'm using C to illustrate the idea; I'll leave the MIPS translation to you):
a0 = the_string;
a1 = the_string + strlen(the_string) - 1;
while (a1 > a0) {
if (*a0 != *a1) return false;
a0++;
a1--;
}
return true;
By the way, a terminology nitpick: # continue recursion. Your implementation isn't recursive, it's iterative.