Why does the last line compare $t2 to $s0? - mips

This is exercise 2.29 from the 5th edition of Computer Organisation and Design by David A. Patterson and John L. Hennessy:
...
addi $t1, $0, $0
LOOP :
lw $s1, 0($s0)
add $s2, $s2, $s1
addi $s0, $s0, 4
addi $t1, $t1, 1
slti $t2, $t1, 100
bne $t2, $s0, LOOP
...
i = $t1
$s2 = result
$s0 = base address of MemArray
I'm supposed to translate this into C code, and I get:
for(int i =0 ;i<100;i++)
{
result += MemArray[i];
}
This is the answer, but why does the last line of MIPS code compare $t2 with $s0? $s0 is the base address of MemArray. Shouldn't the comparison be to the zero register, in order for the loop to continue?

As far as I can tell, this is an error in the book; the correct comparison should be with $0, so $s0 may just be a typo. However, it is not mentioned in the errata for the book's fifth edition.

Related

Why am I getting a duplicate main label error? Also why is there no output?

I am working on my first project in mips, trying to print the sum of all the positive numbers in an array. I am now testing my code with QtSpim and have been getting an error saying I am using the main label twice even though there is only one occurrence. There is also no output, regardless of whether or not I include the main label. Here's the code:
.data
A: .word -89, 19, 91, -23, -31, -96, 3, 67, 17, 13, -43, -74
.text
main:
addi $s0, $zero, 0 #set $s0 for sum of positive nums to 0
la $s1, A #set $s1 to array address
addi $t0, $s1, 48 #set $t0 to exit point
while:
beq $s1, $t0, end
lw $t1, A($s1)
slt $t2, $t1, $zero
bne $t2, $zero, else #skips addition step if A at $s1 is negative
add $s0, $s0, $t1
else:
addi $s1, $s1, 4
j while
end:
li $v0, 1
move $a0, $s0
syscall
li $v0, 10
syscall
Sorry if this is bad formatting for mips, I have only ever worked with Java and C++.
there's an error on this line
lw $t1, A($s1)
What I believe you want is
lw $t1, 0($s1)
A positive integer must be in the offset of the lw instruction.
The main label error seems like a rabbit hole as you see no label was used more than once.

MIPS - Accessing Instruction address to obtain opcode

I'm working on a program where I loop through the code and count the number of I, J, and R type instructions. How would I go about accessing the opcode of the instructions?
.data
typeR: .word 0x00 #for all TypeR opc code
typeJ: .word 0x01 #we will have to left shit one bit when comparing
typeI: .word 0x11 #this is a dummy value because if it's not R or J, it is I
numR: .word 0
numJ: .word 0
numI: .word 0
endProgram: .word 0x11111111 # you would have to know the address of the #last instruction. Assume for now
.text
main:
lw $s0, countR
lw $s1, countJ
lw $s2, countI
#here you load the address of the first instruction of the program you try
#to loop though say 0x00000000
la $t0, 0x00000000
#here load the instruction code in 0x11111111 to register $t1
lw $t1, endProgram
Loop:
lw $s3, 0($t0) # load first instruction code to $s3
beq $s3, typeR, R #if equal goes to R
sll $s3, $s3, 1 # so we get rid of the first digit
beq $s3, typeJ, J # if equal got to J
J I # this is the else
R:
addi $s0,$s0, 1 #increment countR
j next
J:
addi $s1, $s1, 1#increment countJ
j next
I:
addi $s2, $s2, 1 # increment countI
j next
next:#check if it is the end yet, if not keep going to next instruction
lw $s5, 0($t1)
beq $s5, $t1, exit # if it is last instructin go to exit
#if not keep going
addi $t1, $t1, 4 #move to next instruction since each is 4 byte
j loop
exit:
# I think the last part is pretty simple, depend on what you want to do just #print it out or something, so I've save some typing.

MIPS Mult two numbers and result it negative number

I am new for MIPS, there is my code:
.text
main:
add $s0, $zero, 1 # set $s0 to 0 for the initial value for the following loop
Loop: jal srand # Call function srand
addi $s0, $s0, 1 # $s0 = i++
slti $s1, $s0, 6 # $s1 < 6
bne $s1, $zero, Loop # go to loop in i < 6
beq $s1, 6, end_loop # go out the loop when i == 6
end_loop:
li $v0, 10
syscall
srand: # This function will set the numbers for future calculation
lw $t0, a # Load a value to $t0 1103515245
lw $t1, c # Load c value to $t1 12345
lw $t2, m # Load m value to $t2 2147483648
multu $t0,$s0 # result for multiplication (Xn*a) and store the result to $t3
add $t4, $t3, $t1 # result for add multiplication (Xn*a+c) and store the result to $t4
move $a0, $t4 # Debug function
li $v0, 1 # Debug function
syscall # Debug function
la $a0, msg
li $v0, 4
syscall
jr $ra
There is a problem, when the code goes to this "multu $t0,$s0" commend and result will be wrong.
1103515245 * 2 returned a negative number -2087936806
anyone know how to fix it ??
thanks
As chrylis said, it looks like integer overflow. If that's unclear to you, you should read up on two's complement integer representations.
Basically, the value of the highest-order bit is defined to be negative. Suppose you have 32-bit integers. Then 0x800000 will have the value of -2**32, and the other bits have their normal value, so you end up with an expression that looks like -2**32 + [the sum of the other bits], in particular 0xFFFFFFFF has the value of -1, 0xFFFFFE is -2, and so on.

Mips Procedure: Infinite for loop and Exception occurred at PC

Seeing the topics on the site, however I was not able to solve my problem. I noticed that the code inside the procedure falls into an infinite for and in QTSpim I saw that the registers involved are $s0, $s1, $t2, and $t4.
After a few cycles then the message Exception occurred at PC then expection 7 Bad data address.
Here is the code, I can not figure out where mistake, I tried to write it without procedure and it works perfectly.
.data
string: .asciiz "Hello Simon"
string2: .asciiz ""
.text
.globl main
Delete_space:
addi $sp, $sp, -16
sw $s0, 0($sp)
sw $s1, 4($sp)
add $t8, $a0, $zero
lenght_string:
lb $t0, 0($t8)
beqz $t0, for #t8 contain the lenght of string
add $t8, 1
j lenght_string
for:
add $s0, $zero, $zero #i=0
add $s1, $zero, $zero #j=0
condition:
slt $t1, $s0, $t8 #i< lenght_string
beq $t1, $zero, endfor
consequence:
add $t2, $t8, $s0
lb $t3, 0($t2)
bne $t3, ' ', op1
beq $t3, ' ', else
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
op1:
add $t4, $a1, $s1
sb $t3, 0($t4)
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
else:
sub $s1, $s1, 1
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
endfor:
#end
lw $s1, 4($sp)
lw $s0, 0($sp)
addi $sp, $sp, 16
jr $ra
main:
la $a0, string
la $a1, string2
jal Delete_space
la $a0, string2
li $v0, 4
syscall
li $v0, 10
syscall
I think you're trying to copy characters from one string to the other, skipping spaces. (Maybe that's not what you're trying to do - unfortunately, I don't have time to trace the code in detail.) I think the problem is that you're copying from your source string into a data area that doesn't belong to you.
Strings aren't handled the same in Assembly as they are in a high-level language. They're nothing but a sequence of bytes - there is no concept of a String that automatically expands to contain what you put in it. And there's no concept of bounds checking.
Look at these string declarations:
.data
string: .asciiz "Hello Simon"
string2: .asciiz ""
What you've done is assigned string to a memory address containing the byte value 'H'. The subsequent memory locations contain 'e', 'l', 'l', 'o', ' ', 'S', 'i', 'm', 'o', 'n', '\0'.
Then, you've assigned string2 to a memory address containing the byte value '\0' (a null terminator).
If you write a byte to the memory address pointed to by string2, it would replace the null terminator. (You would already be in trouble at this point, because the syscall wouldn't know where your string ends.) If you then write another byte to the memory address pointed to by string2 + 1, you are now writing to memory that you didn't allocate to string2. It might belong to some other variable that's being stored - in which case, you just overwrite what was there before. That's a "buffer overflow", and it's how poorly-written programs such as Internet Explorer get exploited by hackers.
If I'm interpreting the purpose of your program correctly, you need to create a buffer for your output that's big enough to hold it. Something like this would work, assuming your output will never be longer than your input:
.data
string: .asciiz "Hello Simon"
string2: .asciiz "xxxxxxxxxxx"

Unsetting and resetting certain bits

For a homework assignment in school, I need to use a MMIO LED display where each led is exactly 2 bits stored within a byte. For the assignment I need to "move" these LEDs up, down, left, and right. I also need to set the color (I will be using 0x40 for this). Here's my issue:
When I click the "right" arrow to move the LED over 1 column, it remains in the current column when it should be returning to black (0x00). If I click right 4 times (moving over exactly 1 byte), I get another lit LED, leaving the original one there.
Here is my MIPS code:
getLedPattern:
move $t2, $s2
andi $t1, $t2, 0x3 #remainder of x / 4 is in $t0
sll $t0, $t2, 2 #x / 4 is in $t0
beq $t0, 0, case0
beq $t0, 1, case1
beq $t0, 2, case2
case3:
andi $a0, 0xFFFFFFFC
#insert $a1 into bits 0 and 1 of $a0 into $v0
or $v0, $a0, $a1
jr $ra
case2:
andi $a0, 0xFFFFFCFF
#insert $a1 into bits 2 and 3 of $a0 into $v0
#srl $a1, $a1, 2
or $v0, $a0, $a1
jr $ra
case1:
andi $a0, 0xFFFCFFFF
#insert $a1 into bits 4 and 5 of $a0 into $v0
#srl $a1, $a1, 4
or $v0, $a0, $a1
jr $ra
case0:
andi $a0, 0xFCFFFFFF
#insert $a1 into bits 6 and 7 of $a0 into $v0
#srl $a1, $a1, 6
or $v0, $a0, $a1
jr $ra
setLED:
addi $sp, $sp, -20
sw $ra, 0($sp)
sw $t0, 4($sp)
sw $t1, 8($sp)
sw $t2, 12($sp)
sw $t3, 16($sp)
move $t5, $a0
sll $t6, $a1, 5 # y*32
srl $t2, $a2, 2 # x/4
add $t5, $t5, $t6
add $t5, $t5, $t2
lb $a0, 0($t5)
move $a1, $a3
jal getLedPattern
sb $v0, 0($t5)
move $s3, $t5
lw $ra, 0($sp)
lw $t0, 4($sp)
lw $t1, 8($sp)
lw $t2, 12($sp)
lw $t3, 16($sp)
addi $sp, $sp, 20
jr $ra
The logic is that it starts out at at memory location 0xFFFFOOO8 (top left LED), moves down one row (+32 bytes) and over x columns (plus x*bits). However, I can't seem to unset the current LED and move it over one. Any help would be appreciated. I believe that my or in getLedPattern: is wrong, but not 100% sure.
Hopefully, getting this correct I will be able to get this correct in a general sense (no LED display).
I guess that your constants for clearing bits are wrong.
try the following instead:
0xfffffffc // or ~0x03
0xfffffff3 // or ~0x0C
0xffffffcf // or ~0x30
0xffffff3f // or ~0xC0
There are other oddity in your code:
s2 is used, but never set
s3 is set, but never used
case1 and case2 will never be reached because $t0 can hold nor 1 neither 2