How to improve cache performance on this MIPS code - caching

Using a simulator called MARS 4.5 I am trying to improve the cache performance of this code. This is a sub section of an assembly program that computes prime numbers using the Sieve of Eratosthenes algorithm.
For some reason the sw (store word) has a cache hit rate of 25% where the rest of the program is averaging at about 50% in it's current state. I've tried rearranging some things but I can't figure out what is causing this bottleneck. What needs to be done in order to improve this cache hit rate?
inner: add $t2, $s2, 0 # save the bottom of stack address to $t2
mul $t3, $t1, 4 # calculate the number of bytes to jump over
sub $t2, $t2, $t3 # subtract them from bottom of stack address
add $t2, $t2, 8 # add 2 words - we started counting at 2!
sw $s0, ($t2) # store 1's -> it's not a prime number!
add $t1, $t1, $t0 # do this for every multiple of $t0
bgt $t1, $t9, outer # every multiple done? go back to outer loop
j inner # some multiples left? go back to inner loop

I was able to fix this issue by modifying the program to store bytes instead of words. This increased the number of storage blocks in the cache and thus increased the hit rate.
inner: add $t2, $s2, 0 # save the bottom of stack address to $t2
addi $t3, $t1, 1 # add one byte
sub $t2, $t2, $t3 # subtract them from bottom of stack address
add $t2, $t2, 2 # add 2 bytes - we started counting at 2!
sb $s0, ($t2) # store 1's -> it's not a prime number!
add $t1, $t1, $t0 # do this for every multiple of $t0
bgt $t1, $t9, outer # every multiple done? go back to outer loop
j inner # some multiples left? go back to inner loop

Related

For loop counter in MIPS

so I'm currently trying to go through a for loop in MIPS and trying to multiply with it. I did the same thing with addition and it worked. Below, $t0 is the lower integer the user has entered, $t6 is the upper integer + 1, and $t4 is the register that stores the result. Here it is:
beq $t0, $t6, resultFunction
add $t4, $t4, $t0
addi $t0, $t0, 1
j addForLoop
What this does is store the lowest integer value a user has entered and then increments it to an upper integer value they have entered + 1 so that it increments correctly. It then adds appropriately and then increments the counter by 1, repeating if they are not the same. When the values are the same, it exits out of the loop. For example, if the values are 2 and 4, the answer would be 2 + 3 = 5, then 5 + 4 = 9. The loop would output with the answer 9 as it should. I tried to do this same thing but multiplying instead, and this is where my problem is. When trying to replace add with mul (like this),:
beq $t0, $t6, resultFunction
mul $t4, $t4, $t0
addi $t0, $t0, 1
j multForLoop
it is not working correctly and I'm getting 0 as the output instead. If the two integers are 2 and 4 again, it should output 24 (2 * 3 = 6, 6 * 4 = 24). I'm not quite sure why this isn't working and any help would be appreciated.
You haven't shown us all your code, but presumably $t4 is 0 when the loop starts, and anything multiplied by 0 equals 0.
Set $t4 to 1 before the loop.

MIPS Attempt to execute non instruction when using branch

Could anyone please help me to figure out what causes my program to show Attempt to execute non instruction at 0x00400140, when I uncomment the beqz line. If I keep it commented my program runs just fine, but just as I uncomment it it shows the error at random times (i.e. sometimes after 5 seconds, sometimes after 10 seconds, etc). (The program is basically a timer and I am using beqz to only print once each second)
Any help would be greatly appreciated!
main:
addi $t0, $zero, 60 # stores 60 in $t0
div $s0, $t0 # divides total time by 60
mflo $s1 # stores minutes in $s1
mfhi $s2 # stores seconds in $s2
#beqz $s4, skip
#nop
move $s3, $ra # stores $ra in $s3
move $a0, $s1 # stores minute value in $a0
jal printToAscii # calls function to print minute
la $a0, colon # loads colon address in $a0
jal printColon # calls function to print colon
move $a0, $s2 # stores second value in $a0
jal printToAscii # calls function to print second
jal EraseLine
move $ra, $s3 # restores $ra
addi $s4, $zero, 0
skip:
j main
nop
Found the solution, my exception handler kept skipping the line so the j main line got skipped.

Mips assembly language loop through array and isolates bits of interest

I need to loop through this array of bytes
testCases: .byte 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
Im assuming I would do something like this, but not sure
ori $a1, $0, 0x0 # Initialize index with 0
LOOP:
lw $t1, testCases($a1)
...
...
addi $a1, $a1, 1 # Increment index by 1
j LOOP
and isolate the b6,b2,b1,b0 bits using a bitmask. I'm very new to mips and would appreciate any help. Thank you.
No, lw stands for load word. A word is 4 bytes. If you want to load a single byte you should use lb (if you want sign-extension) or lbu (if you want zero-extension).

Link values in MIPS

I'm trying to sort a list of floating point integers in MIPS, which I think I'll be able to figure out, however, each of those float points corresponds to the score of a player in a game. I'm trying to figure out a way to remember that, for example, Bobby's score was 12.3, after I sort the floats in descending order, so that I could return something like:
"Bobby 12.3, Johnny 10.2, Carl 8.8".
Currently I'm storing the floats in the F registers as I read them in, and the names in a block of dynamically allocated memory whose size is generated based on how many players the user is considering.
.data
Prompt1: .asciiz "Please enter number of players.\n"
Prompt2: .asciiz "Please enter name of a player. (Max len 21 characters).\n"
Prompt3: .asciiz "Enter player's points per game.\n"
Prompt4: .asciiz "Enter player's minutes per game.\n"
numPlayers: .space 4
.text
.align 2
.globl main
main:
subu $sp, $sp, 32
sw $ra, 0($sp)
li $v0, 4
la $a0, Prompt1
syscall
li $v0, 5
la $a0, numPlayers
syscall
move $a0, $v0
jal collect
collect:
subu $sp, $sp, 32
sw $ra, 0($sp)
sw $a0, 4($sp)#number of players
addi $t1, $zero, 21 #21 is max length of player name in characters; 21 bytes
mult $t0, 4($sp), $t1 #number of bytes you're going to need for strings for x players
lw $a0, $t0 #a0 now has number of bytes you want for all of the strings
li $v0, 9
syscall
la $t2, $v0 #store memory allocated address into t2
la $t9, $t2 #remember the head you started at for strings
#memory has been made for strings
#make memory for floats now
addi $t0, $zer0, 32 #bits for a floating int, 1 calculation per player
mult $t0, $t0, 4($sp) #number of players times floating point space
lw $a0, $t0 #a0 now has number of bytes for all the floats
li $v0, 9
syscall
la $t8, $v0 #store memory allocated address into $t8 for floats
la $t7, $t8 #remember head you started at for floats
loop:
beq $t0, $zero, sort
la $a0, Prompt2 #print string asking for a player name
la $v0, 4
syscall
la $a0, $t2 #load address of huge memory space
la $a1, 21 #max characters to read is 21
la $v0, 8 #read string and store into address supplied by $a0
syscall
addi $t2, $t2, 21 #move up 21 places in the memory for t2
#so that you're sure you're at an empty space in memory for the next string
#time to read floats
#ask for the points per game
la $a0, Prompt3 #load string to ask points per game
li $v0, 4
syscall
li $v0, 6
syscall #f0 has the float
mov.s $f1, $f0 #f1 has points per game for player 1
la $a0, Prompt5 #load string to ask minutes per game
li $v0, 4
syscall
li $v0, 6
syscall #f0 has the float
mov.d $f2, $f0 #f2 has minutes per game
div.d $f3, $f1, $f2 #divide f1 by f2 store in f3
mov.d $t8, $f3 #t8 now has the points per minute for player
addi $t8, $t8, 32 #move up 32 spots in memory
#how to associate name and player?
addi $t0, $t0, -1 #decrement counter of how many more players you need to do
b loop
sort:
#to be figured out later
You can just do the same with the names as with the scores when you do the sorting, that is switching places, appending to a temporary list, etc.
That being said, it might be easier is you make a list of addresses for your names instead of all the names after each other. Thus, allocate a block of memory per name and store in the list. This way, sorting will be easier.

How to use system call 9 (sbrk) for dynamic memory allocation in MIPS

I have an assignment which is to write comb sort in MIPS. The user is going to enter the array and of course its size. When searching for heap allocation, I found the system call 9. However, I couldn't find the way to use it. I wrote this:
li $v0, 4
la $a0, message1 # prints the first message
syscall
li $v0, 5 # reads the size for the array
syscall
mul $t0, $v0, 4 # because array contains integer, I change them into bytes
la $a0, $t0 # allocate the size of the array in the heap
li $v0, 9 # now, $v0 has the address of allocated memory
syscall
move $v1, $v0 # Because systemcall uses $vo register, I move it to $v1 keep it safe.
create_array:
la $a0, message2 # prints the first message
li $v0, 4
syscall
li $s0, 0 # $s1 is the index, and loop induction variable
li $s1, 5 # $s1 is the sentinel value for the loop
Loop1:
bge $s0, $s1, End_Loop1
li $v0, 5 # Read integer values
syscall
mul $t3, $s0, 4 # $t3 is the offset
add $t4, $t3, $t0 # $t4 is the address of desired index
sw $v0, ($t4) # store the value in the array
addi $s0, $s0, 1 # increment the index
j Loop1
End_Loop1:
And I get this error:
la": Too few or incorrectly formatted operands. Expected: la $t1,($t2)
How can I use it? and Is this the right way to create an array?
Replace
la $a0, $t0 # allocate the size of the array in the heap
with
move $a0, $t0
The la instruction's purpose is to [L]oad the [A]ddress of a symbol into a register. For example:
la $a0, message1 # prints the first message
would load the address of message1 into register $a0. la is actually a pseudo-instruction which in this case translates into:
lui $a0, message1/0x10000 # load the upper halfword of the address
ori $a0, $a0, message1%0x10000 # OR in the lower halfword of the address
As you can imagine it doesn't make sense to try to load the address of another register, since registers don't have addresses.
While we're on the subject of MIPS pseudo-instructions: move is also one of them, and the above move $a0, $t0 instruction translates into something like add $a0, $0, $t0.
Also, replace $t0 with $v1. $t0 just holds the total byte allocated in the heap but you need $v1 which is the beginning addres of the array in the heap.
It should be like:
add $t4, $t3, $v1 # $t4 is the address of desired index

Resources