MIPS Program not Printing Primes Correctly - mips

I have an assignment that requires us to write two functions in MIPS: One that determines if a number is prime or not, and another that finds all the primes between 3 and 102 inclusive and prints them out. Obviously, the second one uses the first; this is meant to be an exercise in jumping and branching. The source code we are given already cleans up the stack and registers, etc., for us, and provides a function to print the number in $a0, so all we need to do is the aforementioned functions. No matter what I do, my program will always just print "1" and exit, even though it should be looping over many numbers. I feel like the mistake I have made is simple, like not loading anything into a register that needs it or overlooking something similarly simple, but I'm still new to MIPS and debugging assembly code is honestly a nightmare. Here are the two functions I've written:
Here's the one for checking if a number is prime:
ori $s0,$a0,0 #make a copy of the argument
ori $t0,$s0,0 #using temp registers is good
ori $s1,$s0,0 #make another copy to use as the loop-end check
li $t2,2 #use 2 as the divisor, makes it easier to check
li $v0,0 #using "not prime" as the base case
prime_test:
slt $t1,$t2,$s1 #check if we're above the ceiling
beq $t1,$zero,found_prime
div $t0,$t2 #check if number is divisible by 2
mfhi $t3 #get remainder from hi
beq $t3,$zero,not_prime #if hi=0, it's not a prime
addi $t2,$t2,1
j prime_test
not_prime:
add $v0,$zero,$zero #return false (0) if not prime
found_prime:
jal print_number #if it's prime, print it
And here's the one for looping and checking from 3 to 102:
li $t0,102 #upper boundary
li $a0,3 #lower boundary
prime_loop:
slt $t5,$a0,$t0
beq $t5,$zero,found_all_primes
jal is_prime
slt $t2,$zero,$a0
bne $t2,$zero,prime_detected
prime_detected:
addi $a0,$a0,1 #increment the counter
j prime_loop
found_all_primes:
Honestly, I think the error is probably in the function that loops; I'm pretty sure my logic for testing if a number is prime is sound, but I could have easily overlooked something. Again, don't worry about it looking like registers aren't being restored properly, that's all taken care of already.

Related

MIPS palindrome checker

I am having a hard time figuring out where to start with this project. I am needing to write code in PLP that is a palindrome checker.
the task is to write a program that recieves a string of characters via UART, checks if this string is a palindrome, then uses a print function to print either"yes" of "no". I have been given a template that I am to follow when creating the program.
The template project file contains six function stubs that need to be implemented. five are called from the main loop and the sixth is called from "period_check: in the template file it contains descriptions of what each function needs to do and how it should be implemented. I have attempted to fill in some, however I do not think I am on the right track. Please help.
***** I have gotten this much code in, but it does not print out the right output****
it prints no for everything vs no for non palindromes and yes for palindrome.
.org 0x10000000
# Initializations
# NOTE: You may add initializations after line 10, but please do not
# remove or change the initializations to $sp, $s0, $s1, or $s2
li $sp, 0x10fffffc # Starting address of empty stack
li $s0, 0xf0000000 # UART base address
li $s1, array_ptr # Array head pointer
li $s2, array_ptr # Array tail pointer
####################################################################
# Do not make changes to the jump to main, the allocation of
# memory for the array, or the main loop
####################################################################
j main
nop
array_ptr: # Label pointing to 100 word array
.space 100
main:
jal poll_UART
nop
jal period_check
nop
jal space_check
nop
jal case_check
nop
jal array_push
nop
j main
nop
####################################################################
# ******************************************************************
####################################################################
# The "poll_UART" function should poll the status register of the UART.
# If the 2^1 bit position (ready bit) is set to 1 then it
# should copy the receive buffer's value into $v0 and send
# a clear status command (2^1) to the command register before
# returning (a return statement is already included). In order to
# receive full credit, $s0 must contain the base address of the UART
# and must be used with the appropriate offsets to access UART
# registers and buffers
poll_UART:
lw $t1, 4($s0)
li $t2, 0b10
and $t3, $t1, $t2
beq $t3, $0, main
nop
lw $v0, 8($s0)
sw $t2, 0($s0)
jr $ra
nop
# The "period_check" function should check if the current character ($v0)
# is a period ("."). If it is a period then the function should go to the
# label, "palindrome_check". If the character is not a period then it
# should use the included return.
period_check:
li $t0, 0x2E
beq $v0, $t0, palindrome_check
nop
# The "space_check" function should check if the current character ($v0)
# is a space (" "). If it is then it should jump to "main" so
# that it skips saving the space character. If not it should
# use the included return.
space_check:
li $t4, 0x20
beq $t4, $v0, main
jr $ra
nop
# The "case_check" function should perform a single inequality check.
# If the current character ($v0) is greater than the ASCII value of 'Z',
# which indicates the current character is lowercase, then it should convert
# the value of $v0 to the uppercase equivalent and then return. If the
# current character ($v0) is already uppercase (meaning the inequality
# mentioned before was not true) then the function should return without
# performing a conversion.
case_check:
li $t5, 0x5A
slt $t6, $v0, $t5
li $t7, 1
beq $t6, $t7, convert
convert:
addiu $v0, $v0, -32
jr $ra
nop
# The "array_push" function should save the current character ($v0) to the
# current location of the tail pointer, $s2. Then it should increment the
# tail pointer so that it points to the next element of the array. Last
# it should use the included return statement.
array_push:
sw $v0, 0($s2)
addiu, $s2, $s2, 4
jr $ra
nop
# The "palindrome_check" subroutine should be jumped to by the period
# check function if a period is encountered. This subroutine should contain
# a loop that traverses the array from the front towards the back (using the
# head pointer, $s1) and from the back towards the front(using the tail
# pointer, $s2). If the string is a palindrome then as the array is traversed
# the characters pointed to should be equal. If the characters are not equal
# then the string is not a palindrome and the print function should be used
# to print "No". If the pointers cross (i.e. the head pointer's address is
# greater than or equal to the tail pointer's address) and the compared
# characters are equal then the string is a palindrome and "Yes" should be
# printed.
#
# Remember to restore the head and tail pointers to the first element
# of the array before the subroutine jumps back to main to begin processing the
# next string. Also, keep in mind that because the tail pointer is updated at
# the end of "array_push" it technically points one element past the last
# character in the array. You will need to compensate for this by either
# decrementing the pointer once at the start of the array or using an offset
# from this pointer's address.
palindrome_check:
addiu $s2, $s2, -8
move $s3, $s1
subu $s6, $s2, $s3
beq $s6, $0, palindrome
nop
check_loop:
lw $s4, 0($s3)
lw $s5, 0($s2)
bne $s5, $t0, not_palindrome
nop
adjust_pointers:
addiu $s2, $s2, -4
addiu $s3, $s3, 4
slt $t8, $s3, $s2
bne $t8, $t0, check_loop
nop
j palindrome
nop
palindrome:
li $a0, 1
call project3_print
move $s2, $s1
j main
not_palindrome:
li $a0, 0
call project3_print
move $s2, $s1
j main
nop
Ok, this is just my opinion, but you are definitely not on the right track.
The control flow you're showing is problematic.
To see one reason why, try writing this same in C or any other language that you know.  You won't be able to do it because of the non-local goto's that's using, where one procedure jumps (without calling) to another procedure.
Further, finding whether an input is a palindrome is not a fixed sequence of one-time steps that are executed on each input character.
You will (1) need to store the characters for later comparison, and (2) need a decision point where you can determine (and print) yes it is, or no it isn't.  You don't have any control structure for that.
that recieves a string of characters via UART, checks if this string is a palindrome, then uses a print function to print either"yes" of "no".
Yes, your main should reflect the above description you've been given:
receive a string of characters
checks if this string is a palindrome
print either "yes" of "no"
In other words you might have something like:
int len = input_string();
if ( check_palindrome(len) ) {
print "yes";
else
print "no"
Suggest you write it in C or other language you know, then translate that to assembly.
Also consider that we some things we program are functions returning a value rather than procedures that don't return values.  Returning a value so that main can take a different course of action (e.g. print yes vs. no) is much better than using non-local goto's to alter the flow of control from within a subroutine.
If your instruction/coursework has given you that main, and is recommending non-local goto's that would be very sad.
I feel for you and your classmates, as this is one of the worst examples of teaching assembly I've seen in a long long time.
array_ptr: # Label pointing to 100 word array
.space 100
The label name is misleading.  This space is used as an array of words, not a pointer to an array.  The storage reserved is 25 words, since .space operates in terms of bytes and words are 4 bytes each.  So, the comment is just plain wrong.
The various "functions" called using jal are single use function, so there's really no need for functions in this assignment at all.  The "functions" also are going to each other and back to main instead of returning properly like they would in structured programming.  So, this is what we call spaghetti code — such code is difficult to reason over and one of the reasons that other languages don't even bother to offer this kind of flow control.
The array being used is storing whole words, when the input elements are only characters, so that's harmless but unnecessary.
beq $t6, $t7, convert
convert:
This control structure will never choose between two options, it will always convert.  Why?  Because in the case $t6 is true it will branch to convert: and in the case that $t6 is not true it will fall through to convert:, so same location, will run same code in either case.
You should be able to observe this during debugging.
Debugging Tips
Get to know your data.  You should know the address of the array as you debug.  You can find this during execution, e.g. look at a register after li ... array_ptr (btw, that opcode should be la, but no matter if it works).  Otherwise you can observe the data section and its layout to find that out before running the first instruction.
Single step each line like one would to debug code in any other language, verifying program state between each line.  In MIPS assembly, not much program state changes between lines so usually this is pretty simple — usually each instruction only changes one register or one memory location — but you must verify that such change is as you're expecting.  Once the first part of the program is properly storing characters into the array, you can use the break point feature to stop at the palindrome check routine and single step only from there on.
Use the smallest possible input first, (in the most degenerate case that would be an empty string, but you may not be handling those so instead) might try a single letter input (should be a palindrome).  Once that is working, try two letter input.  As I said, first make sure that the character values are being placed into the array properly, and only when you've verified that's working, go on to debug the palindrome check code.

How a recursive function works in MIPS?

I'm a newbie in MIPS (as I started learning MIPS assembly for my college) and I've got a problem in understanding how a recursive function works in MIPS.
For example, I've got this program (in C) to write it in MIPS:
int fact (int n)
{
if (n < 1) return 0;
else return n * fact(n - 1);
}
Can someone help me, with this or another example of a recursive function and explain me how it works?
The first thing I'd like to share is that the complexity in translating this into MIPS comes from the presence of mere function calling, rather than because recursion is involved — that fact is recursive is IMHO a red herring. To this end, I'll illustrate a non-recursive function that has every bit the complexity of the recursive function you've stated:
int fact (int n)
{
if (n < 1) return 0;
else return n * other(n - 1); // I've changed the call to "fact" to function "other"
}
My alteration is no longer recursive! However the MIPS code for this version will look identical to the MIPS code for your fact (with the exception, of course, that the jal fact which changes jal other). This is meant to illustrate that the complexity in translating this is due to the call within the function, and has nothing to do with who is being called. (Though YMMV with optimization techniques.)
To understand function calling, you need to understand:
the program counter: how the program interacts with the program counter, especially, of course in the context of function calling..
parameter passing
register conventions, generally
In C, we have explicit parameters. These explicit parameter, of course, also appear in assembly/machine language — but there are also parameters passed in machine code that are not visible in C code. Examples of these are the return address value, and the stack pointer.
What is needed here is an analysis of the function (independent of recursion):
The parameter n will be in $a0 on function entry. The value of n is required after the function call (to other), because we cannot multiply until that function call returns the right hand operand of *.
Therefore, n (the left hand operand to *) must survive the function call to other, and in $a0 it will not — since our own code will repurpose $a0 in order to call other(n-1), as n-1 must go into $a0 for that.
Also, the (in C, implicit) parameter$ra holds the return address value needed to return to our caller. The call to other will, similarly, repurpose the $ra register, wiping out its previous value.
Therefore, this function (yours or mine) needs two values to survive the function call that is within its body (e.g. the call to other).
The solution is simple: values we need (that are living in registers that are repurposed or wiped out by something we're doing, or the callee potentially does) need to be moved or copied elsewhere: somewhere that will survive the function call.
Memory can be used for this, and, we can obtain some memory for these purposes using the stack.
Based on this, we need to make a stack frame that has space for the two things we need (and would otherwise get wiped out) after calling other. The entry $ra must be saved (and later reloaded) in order for us to use it to return; also, the initial n value needs to be saved so we can use it for the multiply. (Stack frames are typically created in function prologue, and removed in function epilogue.)
As is often the case in machine code (or even programming in general) there are also other ways of handling things, though the gist is the same. (This is a good thing, and an optimizing compiler will generally seek the best way given the particular circumstances.)
Presence or absence of recursion does not change the fundamental analysis we need to translate this into assembly/machine language. Recursion dramatically increases the potential for stack overflow, but otherwise does not change this analysis.
Addendum
To be clear, recursion imposes the requirement to use a dynamically expandable call stack — though all modern computer systems provide such a stack for calling, so this requirement is easy to forget or gloss over on today's systems.
For programs without recursion, a call stack is not a requirement — local variables can be allocated to function-private global variables (including the return address), and this was done on certain older systems like the PDP-8, which did not offer specific hardware support for a call stack.
Systems that use stack memory for passing parameters and/or are register poor may not require the analysis described in this answer, since variables are already being stored in memory that survives nested function calls.
It is the partitioning of registers on modern register-rich machines that creates the requirement for the above analysis. These register-rich machines pass parameters and return values (mostly) in CPU registers, which is efficient but imposes the need to sometimes make copies as registers are repurposed from one function to another.
A way to implement the function you described is using the allocation of memory with addi to move the stack pointer to allocate (at the start) and free (at the end) some stack space. Then the sw instruction can save registers into that space. Use lw to restore them after a call, and/or when you're ready to return. So we can start with this instruction to allocate some memory:
addi $sp, $sp, -8 in $sp register, we sum -8
this is, we need 8 bytes, 4 for the $ra return and also 4 bytes for the int n. Now, we allocate in the following way:
sw $a0, 4($sp) #we are saving the int with register $a0 in position 4
sw $ra, 0($sp) #we are saving the return address with address $ra in position 0
Now, we need a temporary variable to store the 1 in the comparison above. Then we have:
addi $t0, $0, 2 in $t0 register, we sum 2 to $0
now the comparison operand is slt, in our case:
slt $t0, $a0, $t0 in $t0 register, we compare the value contained in $a0 register with that in $t0 register, if true $t0 is 1, else is 0
for if $t0 is zero, we need to have the following jump structure (observe that else is a label, this is, a structure to be followed according to a rule):
obs.: $0 is used to store zero
beq $t0, $0, $t0, else in $t0 we see if it's zero, if so, we continue our program, if not, we go to another instruction, this is, else.
continuing, we now have to return 0, as follows:
`addi $v0, $0, 0
and at the end we have to restore the stack as we very much know.
For the label else, we start with the notion that we need n becoming n-1, in the following manner:
`addi $a0, $a0, -1 #this is, we add $a0 and -1 to $a0
we have to use jal fact for it's clear we have a recursion.
the next step is to restore the address of return ra and the int n as we know, and also the stack.
It's evident that we have a multiplication, for this motif, we will apply the next instruction:
`mul $v0, $a0, $v0 #this is, we multiply $a0 with $v0, remembering that v0 stores the fact(n-1):
`mul $v0, $a0, $v0 #multiplies n and fact(n-1)
we have to keep in mind that it's necessary to use jr $ra to return.
I hope, I have cleared one or another point.

MIPS and $31, can't understand why data is stored in register $31

I don't know too much about MIPS, because we have to do it next year at university, but, this year we got to work with lex and yacc and ofcourse we need to know MIPS. I just learned something about it few hours ago, but for example if we have 'a=-2' and 'b=-a', I know that for 'a=-2' we have something like that 'addi $1, $0, -2', and for 'b=-a' we have something like that 'move $2, $31'. I understood untill here, but I want to know something. $31 is register where 'b' will be stored? and if yes, what is so special at that register? Why can't be stored in $30 , or $29 for example? It is because $31 is last register?
Register assignment is based upon the compiler's allocation scheme, subject to the mips ABI http://www.cs.uwm.edu/classes/cs315/Bacon/Lecture/HTML/ch05s03.html
So, if you have two variables: a and b, the compiler can assign them to any register that is available for the given purpose. Register $31 aka $ra is the return address register. It's not a good choice to retain a data value because $ra is hardwired into the jal instruction.
$0 aka $zero is hardwired to the value of zero. Other registers can be used for any purpose, but most compilers, and most programs, adhere to the register usage conventions of the ABI.
Thus, $1 aka $at is the "assembler temporary". This is used because mips only has conditional branch instructions for equality/inequality (e.g. beq/bne) and does not have (e.g. blt). So, it has an slt instruction that takes an output register, which is generally the $at register
For your sequence:
a = -2;
b = -a;
Let's assume that a has been assigned $t0 and b has been assigned to $t1. The generated sequence would be:
addi $t0,$zero,-2 # a = -2
sub $t1,$zero,$t0 # b = -a
Also, for more on what can and cannot be done with $ra, see my answer here: Whether $ra register callee saved or caller saved in mips?
$31 register in MIPS is the return address register. It is saved by the calling function. It is available for use after saving.
But there is no checking against that. It can be used in a lw instruction just like any other general purpose register.

How does a program written in MIPS knows what to return?

I have this program I just wrote:
countzeroes:
li $v0, 0 # count = 0
li $t0, 0 # int i = 0
li $v1, 1 # compare bit = 1
cz_loop:
bge $t0, 32, cz_exit # exit loop if i >= 32
andi $t1, $a0, 1 # bit = arg0 & 1
beq $t1, $v1, cz_skip # skip if bit = 1
addi $v0, $v0, 1 # adds 1 to count
cz_skip:
srl $a0, $a0, 1 # shifts input right by 1
add $t0, $t0, 1 # i++
j cz_loop
cz_exit:
jr $ra
Pretty simple, just computes the number of zeroes in a 32 bit word. I was wondering how the program knows how to return $v0 at the end? I know v0 and v1 are return registers, but I was wondering if those two are always returned. If not, how does the program know to return v0?
In addition, I know jr $ra jumps to the return address- but what does that mean?
Thanks for your help.
"how the program knows how to return $v0 at the end?"
It doesn't know, you're writing the "return" value in $v0, in fact you could return the "result or return values" in any available register such as the temporals, it's just a convention to use the $v0 register to return values (in MIPS).
"I was wondering if those two are always returned"
Remember that in any subroutine in your program you always have access to all registers, so there's not "restriction" about what register store values that can be semantically called "return values", so I could easily create a method that returns 3 numbers in $t0, $t1, $t2 but that's my choice, you can return values in the stack also, there are a lot of possibilities, and this depends and lays down on the good programming practices and also the calling conventions, here you can find the MIPS calling convention: https://courses.cs.washington.edu/courses/cse410/09sp/examples/MIPSCallingConventionsSummary.pdf
" jr $ra jumps to the return address- but what does that mean?"
The program is executed instruction by instruction(the program has an instruction pointer aka program counter), when you call a subroutine the address of the next instruction is being stored in the $ra register, then when you make jr $ra, the program execution returns to that address (the instruction pointer gets the value of $ra).
In MIPS there are three different jumps you'll see. j, jr & jal.
j: it is considered an unconditional jump. Simply just do:
j function
jr:aka jump to register. Exactly as the name sounds you jump to register. This is when you have a register already saved somewhere in your program you want to jump back to. It will usually look like so:
jr $ra
$ra being the register which had been previously set aside before your jal (see below) which will jump the program back to that address.
jal: aka Jump and link copies the address of the next instruction into the register and then jumps to the address label. In other words, both jal and jr are used in conjunction with each other mainly for going to functions which are usually placed after the exit calls.
Ex:
main:
#program
jal function
#continue with program
function:
#
#do something
#
jr $ra
Also, most helpful site when I started learning: http://logos.cs.uic.edu/366/notes/mips%20quick%20tutorial.htm
Some other quick hints that I wish someone told me when I started:
Always start with "main:"
Be wary of the difference between high/low registers in multiplying
and dividing integers
Always keep track of your registers because with so many $s and $t
and $f and $p and $a and $v registers working at one time things can
get messy very quickly.

MIPS Adjusting bits and Looping?

I'm new to MIPS and am confused on how to go about writing mips could for a certain question that is given where I'm asked to write mips code to pulse bit 6 at a memory location of 0xABCDABC0 for a total of 2*n+74 times and assuming n is in $s1.
I'm not sure exactly how to deal with accessing a specific bit at the given address, I know that I'd have to use or immediate to specifically turn on the bit with 1 and then and it to turn the bit back to 0 using 1. The Loop (without multiplication) I could do add $s2, $s1, $s1
then addi $s2, $s2,74 but how do you loop it?
The easiest part here is writing the loop, I can help you with that. I'm pretty rusty, but I'll do my best to get you started.
Looping can be achieved through temporary values, adding immediate values, branch instructions, and/or jump instructions.
The basic flow you're looking for sounds like:
Create a counting variable (the i part in for (int i=..; i < ...; i++), as an example)
Label the beginning instruction of your loop (that will look something like below)
label_name:
loop instructions
Perform the loop instructions
Increment your loop variable from step 1
Populate $s2 with 2*n+74 (that's the part you have now)
Branch to the beginning of the loop if your counter is not equal to your desired iteration count
Note: if you have enough loop instructions, you might have to use a more complicated branch/jump construct.
Example loop code:
andi $t1, $t1, 0 # set a counter variable to 0 (t1)
loop:
# do some work - whatever you want to accomplish by looping
addi $t1, $t1, 1 # increment the counter
add $s2, $s1, $s1 # this is the code you devised
addi $s2, $s2, 74
bne $s2, $t1, loop #branch to the beginning of the loop if you need more iterations
The next part you need is grabbing a value at a memory address, there are a few ways to go about that. You should look into the load/store instructions available in MIPS. In particular, I think you will want to utilize the lw (load word) instruction.
lw r1, label -> loads the word from memory stored at the addressed stored in 'label' into register r1
I Googled a little and http://pages.cs.wisc.edu/~cs354-2/cs354/karen.notes/MAL.instructions.html had some reasonable explanations and and examples of those instructions.
Accessing a specific bit requires utilizing some bit operations. In particular, I think you will find bit shifting and masking helpful.
MIPS offers a few instructions you might like:
sll d, s1, s2 d = logical left shift of s1 by s2 places
sra d, s1, s2 d = arithmetic right shift of s1 by s2 places
srl d, s1, s2 d = logical right shift of s1 by s2 places
and d, s1, s2 d = s1 & s2; bitwise AND
-- From the source I cited above
I hope that is sufficient to answer your question, and least get you going on the problem. I didn't want to just hand you the code, since it sounded like homework. If anything isn't clear or needs clarification, please just say so.
Hope at least some of all of that helps you!