I am new in MIPS, and I am trying to judge whether each char in a string is an alpha. I used the ASCII code to help me to judge it, while I found there is no instruction representing larger than meaning. So I try to implement a not operation from the instructions I have known. Here's part of my code:
isAlpha:
sltiu $t0, $s2, 123
sltiu $t1, $s2, 97
nor $t1, $t1, $t1
and $t0, $t0, $t1
sltiu $t2, $s2, 107
sltiu $t3, $s2, 81
nor $t3, $t3, $t3
and $t2, $t2, $t3
or $t0, $t0, $t2
bne $t0, $zero, countAlpha
jr $ra
However, I could not get the result I want. I set a breakpoint and found that my not operation seems to have some problems:
In my exception, $t1 should be 1 and $t2 should be 0, while the reality is not.
Where's the wrong place in my code? Is there any way to implement not operation in MIPS? Or is there a better way to implement larger than meaning in MIPS? Thanks in advance.
You have a not operation here:
nor $t1, $t1, $t1
Often you can just type the not mnemonic and your assembler will interpret it as a pseudo instruction
I think you want an exclusive or operation to tell you if your input is just one of less than 123 and less than 97.
Something like this (totally untested)
isAlpha:
sltiu $t0, $s2, 123
sltiu $t1, $s2, 97
xor $t0, $t0, $t1
sltiu $t2, $s2, 107
sltiu $t3, $s2, 81
xor $t2, $t2, $t3
or $t0, $t0, $t2
bne $t0, $zero, countAlpha
jr $ra
You can get the effect of gt by reversing the arguments to slt*:
sltu $v0,$t0,$t1 # v0 = $t0 < $t1 (what you have)
sltu $v0,$t1,$t0 # v0 = $t0 > $t1 (what you want)
Note that ge or le is a bit trickier. Consider the various branch pseudo ops like: blt, bge, bgt, bge [they generate slt* followed by either beq or bne]. They're usually easier to work with.
xor can do bitwise negation. The not pseudo-op will generate a nor.
Below is some code that does what you want. Note that it is similar to the code sfi posted, but has an additional [and necessary] and during the range check to prevent a false positive.
For example, without the and, the range check for a-z will report true on anything higher than z (e.g. 0x7B aka {). This is because both slt instructions will generate 0. But, xor of two zeros is 1. So, the xor result must be anded against the high range value slt result
# isAlpha -- decide if char is alpha
#
# RETURNS:
# v0 -- 1=is alpha
# s6 -- count of alpha chars
#
# arguments:
# s2 -- character to test
#
# registers:
# t0 -- holds lt 'a/A'? value
# t1 -- holds lt 'a/A' + 1? value
# t2 -- bool for within 'a-z'
# t3 -- bool for within 'A-Z'
isAlpha:
# within a-z range
sltiu $t0,$s2,0x61 # lt 'a'? (i.e. not a-z)
sltiu $t1,$s2,0x7B # lt 'z' + 1? (i.e. le 'z')
xor $t2,$t0,$t1 # want one but not both
and $t2,$t2,$t1 # want only lt 'z' + 1
# within A-Z range
sltiu $t0,$s2,0x41 # lt 'A'? (i.e. not A-Z)
sltiu $t1,$s2,0x5C # lt 'Z' + 1? (i.e. le 'Z')
xor $t3,$t0,$t1 # want one but not both
and $t3,$t3,$t1 # want only lt 'Z' + 1
or $v0,$t2,$t3 # decide if alpha
add $s6,$s6,$v0 # increment alpha count
jr $ra
Related
I'm working on a program that should convert a user inputted floating point number to an integer, I got it to work but only for floating point numbers that don't have a fractional part that exceeds 2^-1, which is obviously 1/2. It'll work for numbers like 75.5 or 2.5, but not a number like 75.625. I need to keep the code in this format, but I am not sure what I should make the program shift left and right (around the hashtags) by to cancel out the fractional part regardless of what the fractional part is.
.data
Prompt: .asciiz "\n Please Input a value for the float N = "
result1: .asciiz " The converted N is "
.text
li $v0, 4 # system call code for Print String
la $a0, Prompt # loads address of prompt into $a0
syscall # print the message in Prompt
li $v0, 6 # System call code for Read Float
syscall # read whatever you input float as
mfc1 $t1, $f0 # Stores the float value into the $t1
srl $t2, $t1, 23 # srl by 23 to leave out the biased exponent and store it
in $t2
add $s3, $t2, -127 # Subtract 127 to get the exponent
sll $t4, $t1, 9 # Shift left and right by 9 to remove the exponent
srl $t5, $t4, 9
addi $t6, $t5, 8388608 # Add the implied bit (2^24)
add $t7, $s3, 9 # Add 9 to the exponent value
sllv $s4, $t6, $t7 # Shifts the implied bit to 2^32 (32nd bit)
###########################
rol $s5, $t6, $t7 #rotate to the left by whatever the exponent + 9 is to
get
the integer part of the number to the first few bits
sll $s5, $s5, 1
srl $s5, $s5, 1 # sll and srl cancels out the fractional part #should be
1001011 #s5 is the newly converted integer
######################
li $v0, 4 # Tells computer to get ready to print a .asciiz number
la $a0, result1
syscall
li $v0, 1 # Tells computer to get ready to print the converted integer
number
move $a0, $s5 # Moves the contents of $s5 to %a0 so it can be called
syscall # Returns the integer
The following is my code in MIPS to calculate the sum of odd integers using a while loop.
.data
num: .space 4
.text
.globl main
main:
li $t1, 1
li $t2, 9 # make $t2 9 to break the loop
li $t3, 1
loop:
beq $t3, 11, Exit # check to see if $t3 = 11 if so exit
addi $t3, $t3, 2 # change $t3 to next odd number by adding 2
add $t1, $t1, $t3 # add $t3 to $t1 (1+3,...3+5...etc...)
j loop #jump back to the start of the loop
Exit:
li $v0, 1 # system call code to print an int
lw $a0, num # address of int to print
syscall # print the int
jr $ra #exit
This is my first real experience with MIPS and I'm not sure what is going wrong in this code. I put the print inside the while loop to see if it was ever calculating, but the result is always 1.
So, my result at the end is just 111111.
Edit: Removed the prints inside of the loop with the same result.
And OS is Windows 7 64x
Update: Having num as a variable was over complicating things. Code has been revised as follow and works. Thank you for the help!
enter code here
.data
.text
.globl main
main:
addi $t1, $0, 1
addi $t2, $0, 3
loop: bge $t2, 11, Exit # check to see if $t3 >= 11 if so exit
add $t1, $t1, $t2 # add $t2 to $t1 (1+3,...3+5...etc...)
addi $t2, $t2, 2 # change $t2 to next odd number by adding 2
j loop #jump back to the start of the loop
Exit:
li $v0, 1 # system call code to print an int
move $a0,$t1 # address of int to print
syscall # print the int
jr $ra #exit
la $t1, num
You're clearly getting into trouble here, since you're overwriting your accumulator with the address of num every time you're making the syscall. You're losing the current state of your calculation each time.
You'll need to either save your registers, or simply use different ones. Since I don't know what OS it is that you're using, I don't know if you more generally need to save registers over a syscall, but that could also be a source of errors.
I did similar problems for an architecture class and this seemed to be a recurrent problem among all students. When facing problems similar to this our professor's recommendation was to use a different register to temporarily store the register's address to avoid overwriting other desired values from our most commonly used regs.
I know I can check whether an integer is even if I shift right by 1, then shift left by 1 and the number stays as the original number.
My code isn't working as intended. This is my first time using MIPS and any help would be appreciated. I want to let the user input any number and my code will tell the user whether it is an even number.
.data
msg: .asciiz "even"
.text
.globl main
main:
li $v0, 5
syscall
or $t0, $0, $v0 # Register $t0 gets input
srl $t1 , $t0 , 1 #shift right by 1
syscall
sll $t1 , $t0 , 1 #shift left by 1
syscall
bne $t1, $t0, msg # if t1 equals t2 then it prints out even
syscall
There are a couple of strange things you're doing, and one easy-fix bug. But until you get the strange things fixed, you're going to be hozed.
First, like #markgz said, what are those syscalls supposed to be doing? Get rid of all of them except the one where you're getting a value from the user. Otherwise, you're going to get a number from the user over and over.
Second, branching to msg makes no sense. The memory at msg is an ASCIIZ string containing the characters m, s, g, and \0. These are not the 32 bits you are looking for. You need to branch to an instruction. I'm going to assume that labels isEven and isOdd exist somewhere.
The bug is what #Konrad said. Omitting the strange syscalls, your code is doing this:
srl $t1, $t0, 1 # shift *original val* right by 1 *and put in $t1*
sll $t1, $t0, 1 # shift *original val* left by 1 *and put in $t1*
bne $t1, $t0, isOdd # *will always be true because we just changed $t1 to be <> $t0*
So if you follow #Konrad's suggestion, it would look like this:
srl $t1, $t0, 1 # shift *original val* right by 1
sll $t1, $t1, 1 # shift *modified val* left by 1
bne $t1, $t0, isOdd # *Now we know if the value changed*
Note that I'm branching to isOdd. You claimed that if the values are different, then the number is even. That's incorrect.
As an aside, my favorite way to do this would be a little bit different:
andi $t1, $t0, 0x01
beq $t1, $zero, isEven
I'll leave it to you to figure out what I'm doing. One thing about your method: it fails if the most significant bit is set (which it will be if it's a negative signed integer).
There are so many bugs in your code.
srl $t1 , $t0 , 1 #shift right by 1
syscall # why you are using syscall here ??
sll $t1 , $t0 , 1 #shift left by 1--and should be sll $t1, $t1, 1
syscall #and why also here ??
bne $t1, $t0, msg #wrong ,here you need to pass label as third operand for offset
li $v0,4 # code 4 == print string
la $a0,string # $a0 == address of the string
syscall
Note: in spite of this you can just do & operation on any data with 0x1 and then check for the result is 0 (even) or 1 (odd)
I want also to share this link for programming tutorial on mips
http://chortle.ccsu.edu/AssemblyTutorial/index.html
I am writing this program in MIPS to calculate 2 to a power given by me and sum the sequential powers down to 0. For example, if I put 4 in $a0 like in the code below, I want it to calculate (4^2)+(3^2)+(2^2)+(1^2) which should come out to be 15. It should stop before it reaches zero. This is what I have written so far
main:
addi $a0, $zero, 4 #put k in $a0 in this case
addi $a1, $zero, 0 #put 0 in current sum
addi $v1, $v1, 0 #tally the total in $v1
for:
lw $10, $a0 #load k into reg $10
lw $11, $a1 #load sum into $11
addi $10, $10, -1 #subtracts 1 from k
li $9, 0 #sets i in for loop ($9) to 0
done:
li $v0, 10
syscall
I'm new to MIPS and could use a lot of help on finishing this, I know I want to use a for loop, but I don't know how to go through it while subtracting 1 from k and also calculating the sum. How would I bring 2 to a power of k, because I guess there is no power operation in mips. At this point in the course I can only use add, sub, and, or, slt, addi, j, beq, lw, sw, and sll. Can you not use a constant when using sub? Thank you for any help
A power is a multiplication, and a multiplication is a sum. So you can write a function that does a multiplication by adding, and another function that does power by multiplicating. For example, the multiplication function:
multiply: # $a0 first factor, $a1 second factor, $v0 result of multiplication
or $t0, $zr, $zr
or $t1, $a1, $a1
or $t3, $zr, $zr
loop:
beq $t1, $zr, end
add $t0, $t0, $a0
addi $t1, $t1, -1
j loop
nop
end:
or $v0, $t0, $0
jr $ra
nop
(Please note I haven't tested this, and this will not work with negative numbers)
As a side note, you have MUL instruction as well, but I don't know if you saw that already.
I think the concept your instructor is trying to show you is that sll, in effect, multiplies by 2. You've got to think in binary. For example, let's start with 1:
0000 0000 0000 0000 0000 0000 0000 0001
Do a 'sll' on that, and what do you end up with? 0010 = 2. sll again and you get 0100 = 4. And so on, until you shift all the way over and have 0x80000000.
So the answer to the question, "How would I bring 2 to a power of k?", is simpler than you might have thought: you shift 1 by k.
# $t0 contains 'k', the amount we want to shift by
addi $t1, $zero, 1
sllv $t3, $t1, $t0
Note: I had to double-check that you can shift by a variable amount, but this link says sllv is valid. However, since it's not in your list of allowed functions, you'll have to do sll $t1, $t1, 1 in a loop. (Be sure to put your check at the start of the loop, in case the amount you want to shift by is zero!)
Quick question:
Are you doing 2^4+2^3.. etc? or 4^2+3^2 etc?
Just a quick note:
2^4+2^3+2^2+2^1+2^0 = 15.
4^2+3^2+2^2+2^1 != 15.
(If it is the first, you do need 2^0 because you need to contemplate for odd numbers, 2^0 = 1. This is how we get odd numbers in binary.)
In this case, the answer about left shift (lls) is correct. When you left shift a binary number you increase the exponent of base 2 by 1.
so:
0001 = 1
0010 = 2
0100 = 4
1000 = 8
These summed give you 15.
So you could shift left, and add the result of each shift to a register.
Fellow SO users,
If I have a value, say 1010 saved in memory, how do I load each of the bits starting from the MSB to the LSB one at a time? By this I mean,
while loop
load $t1 with 1
shift some number by the amount indicated by the value in $t1 (1)
load $t1 with 0
shift some number by the amount indicated by the value in $t1 (0)
do the same until you load the LSB which is 0
start again at MSB (rotate right?)
end loop
I need some tips on how to declare this value in memory in the .data segment first. Do I declare this as:
value: .byte 00001010
And how do I load the individual bits into registers?
Kind regards
You can do this with the SLT instruction described here. Here is some pseudocode:
lbu $s0, value # load the byte
sll $s0, $s0, 24 # shift it into the upper byte of $s0
for (i = 0; i < 8; i++) {
# $t0 is set to 1 if the sign bit (i.e. bit 31) of $s0 is set
slt $t0, $s0, $zero
# $t0 now holds the value of the ith bit of value
. . . . # do something with $t0
sll $s0, $s0, 1 # shift on to the next bit
}
Implementing the for loop in assembler is left as an exercise for the reader.