How to save a char in a register in mips? - mips

I'm working on a tic tac toe implementation code in MIPS and need to save the char 'x' in a $s0 register but MARS won't let me do it. I'm aware of how to save an integer value
addi $s0, $zero, 1
#at least that's how i've been teached to do it
However I need to do that exact assignation with a char, in this case 'x' or '1'.
It can be more understandable this way.
In a normal coding language it would be something like this:
char variable='x'
How can I do this in MIPS? Please help

Related

How to translate MIPS into C and how to reduce MIPS instructions?

Supposing that f, g, h, i are stored in $s0~$s4 respectively and the base addresses of arrays A and B are in $S6 and $S7.
sll $t0, $s0, 2
add $t0, $s6, $t0
sll $tl, $sl, 2
add $tl, $s7, $tl
lw $s0, 0($t0)
addi $t2 , $t0, 4
lw $t0, 0($t2)
add $t0, $t0, $s0
SW $t0, 0($tl)
I'm not familiar with MIPS so I Wonder how to translate MIPS into C and how to minimize these MIPS instructions?
how to translate MIPS into C
You recognize the patterns, here for array indexing / array element access.
On a byte addressable machine (all modern hardware), a 4-byte integer occupies 4 bytes in memory, and each of those bytes has a unique memory address.  Because of the way the hardware works, we only use one of those 4 addresses to refer to the whole 4-byte integer, namely we use the lowest address among the 4.  The hardware can load a 4-byte integer from memory given that one address (the lowest).
Since each 4-byte integer in memory occupies 4 addresses, in an array of 4-byte integers, the memory address of the first element and the memory address of the second element are 4 addresses apart even though are sequential index positions (i.e. they are only 1 index position apart).
The formula for indexing a 4-byte integer array, then is to convert the index into a byte offset, then add the byte offset to the base address of the array.  The first part of that: converting an index to a byte offset, is sometimes referred to as "scaling".  Scaling is conceptually done by multiplication, so in A[i], i needs to be scaled by the size of the array elements of A.  If 4-byte integers that means scaling (multiplying) the index by 4.  A quick way of doing that is shifting by 2 bit positions, which has the same effect as multiplying by 4.
The C language automatically scales when doing array references, whereas assembly language requires explicit scaling.  C can do this because it knows the type of the array, whereas assembly language does not.
In C we can do expressions like A[i].  The C language allows us to break that down somewhat into *(A+i), which separates the pointer arithmetic addition A+i from the dereferencing of that sum, dereferencing with the unary indirection operator, *.  As previously mentioned, C automatically scales, so A+i becomes the equivalent of A+i*4, in which we can substitute shifting for multiplication: A+(i<<2).
Next, we need to know if the dereference is for read or for write.  When A[i] is accessed for its value, we will see it on what we call the "right hand side" of an assignment operator, as in ... = A[i].  When A[i] is access to update/store a value, we will see it on what we call the left hand side of an assignment operator, as in A[i] = ....
So, the sequence for doing A[i] for read (right hand side) in C is the following in assembly:
sll $temp1, $i, 2
addu $temp2, $A, $temp1
lw $temp3, 0($temp1)
Where $tempN is some register (usually a designated temporary) chosen to hold an intermediate value.  Since multiple instructions are needed to accomplish anything, sequences of instructions are interconnected with registers that hold the intermediate states.  And also, in assembly we name registers, not variables, so in my above $i and $A should be a registers names representing those variables rather than variable names directly used.
The pattern for write/store array access is similar but ends with a sw instruction instead, to store some value into memory at the index position.
These instruction sequence are interconnected by the use of these registers, and the sequences can be interrupted or interspersed with other instructions — what we have to follow then is the above pattern by paying attention to to the register usages that interconnect them rather than the specific sequences.
In your sample code:
sll $t0, $s0, 2 # sourcing an index in $s0, scaling it into temp $t0
add $t0, $s6, $t0 # adding a base array in $s6, putting back into $t0
sll $tl, $sl, 2
add $tl, $s7, $tl
lw $s0, 0($t0) # accessing the value of $s6[$s0*4], aka A[f]
addi $t2 , $t0, 4
lw $t0, 0($t2)
add $t0, $t0, $s0
SW $t0, 0($tl)
We can see the pattern for a read access to an index in $s0, and an array in $s6, these, we are told, map to f and A, so those three instructions comprise A[f] to read a value from A at index f.
The rest are done similarly.  Your job is to use this knowledge to find the other array indexing patterns in the above sequence.  Find out how the results of the array indexing operations are used and you'll have the complete C code.
NOTE that the sample you've been given incorrectly uses add and addi when pointer arithmetic should use addu and addiu — we don't want signed integer overflow checking on pointer arithmetic, as pointers are unsigned.
One of the add instructions is not for pointer arithmetic, but should probably still have used addu if this is intended to be replicated in C, because the C language does not have a built in operator to trap on overflow.

Is there a way to make sure that my bytes are loading properly when I use the sb command in MIPS?

I am coding in MIPS and trying to replace every matching character in a string with another character supplied by the user. My problem is the actual replacement. I'm trying to use sb to move the replacement character into the correct spot, but it doesn't seem to be working.
while:
lb $t2, 0($t5) #Loads the next byte of the string into
temporary storage
beqz $t2, exit #If the next byte is empty, we're done
beq $t2, $t1, replacer #If the next character matches, replace the
character
replacerContinue:
addi $t0, $t0, 1 #Increments the address for the modded array
addi $t5, $t5, 1 #Increments original string
j while
.
.
.
.
replacer:
sb $t4, 0($t0) <---- #Stores the replacement character at the bit
in the current offset for the modified string
j replacerContinue
syscall
Here's a bit of a key for the registers, I know it's a bit of a mess:
$t0 = The modified version of the original string that should contain the new
character in replacement of the old character
$t1 = The character that the user wants to replace in the string
$t2 = The byte in the string for $t5
$t4 = The character that the user has chosen to replace the old character with
$t5 = The original string. It was input earlier by the user, and I have it
stored in the.data component
I was expecting that when I used sb $t4, 0($t0), it would store the replacement character into the corresponding spot of the old character (notice that I increment the addresses at the end of the loop, so I shouldn't need to add an offset).
Instead, I can't tell whether anything is happening. I'm using MARS, and when I look at the register value to see if the replacement is happening at $t0, it only shows the value of the address.
Thanks for your help. Let me know if I can provide any more information, or if you notice any bad practices in my code writing. I'm still very new to MIPS.

MIPS Program not Printing Primes Correctly

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.

Declaring a pointer in MIPS

Just starting out in mips and having a little trouble with one concept. Let's say I want to take this and put it into mips
char *number = "one";
How would I implement that? Thanks.
You define the variable in the .data section
number: .asciiz "one"
and if you want the base address of it you store it in $t0 with a load address instruction
la $t0, number
and you can load the word, byte, or halfword into $t1 with a load instruction like this
lw $t1, 0($t0)
where the 0 is the offset from the base address

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.