MIPS - Convert Word to Byte - binary

I have (what I think) is a simple question.
I have a value in a register in MIPS and I want to convert it from a word to a byte.
So, for example:
I have the value 123456 in register $t0
The actual value will be:
00000000 00000001 11100010 01000000
I want to then put the value of the rightmost byte of $t0 (01000000) into $t1. This would be the value 64.
I want to do this without going to memory. I could store it as a byte to the stack and load it back, but that seems unnecessary.
My general idea is to shift the bits to the left, then to the right, to "remove" all of the bits from positions 31...8. But that has the glaring incapability of not negating numbers when it should.
Here is an example of how close I have gotten:
.text
main:
# START PROLOGUE ####################################
# Ignore all of this, irrelevent and I know the stack is too big
la $sp, -8($sp) # allocate space for old $fp and $ra
sw $fp, 4($sp) # save old $fp
sw $ra, 0($sp) # save return address
la $fp, 0($sp) # set up frame pointer
la $sp, -120($sp) # allocate stack frame: 120 = space for locals, temps in bytes
# END PROLOGUE ####################################
li $a0, 123456
li $v0, 1
syscall #would print out 123456, as it should
# Now say I want to load only a 'byte' of $a0 (convert a word to a byte)
sll $a0, $a0, 24
srl $a0, $a0, 24
syscall # Will print out 64, as it should
# However!
li $a0, 194
syscall # Prints out 194 as it should
sll $a0, $a0, 24
srl $a0, $a0, 24
syscall # Still prints out 194, but I want it to be -62 (signed)
# START EPILOGUE ####################################
la $sp, 0($fp) # (deallocate locals)
lw $ra, 0($sp) # (restore return address)
lw $fp, 4($sp) # (restore frame pointer)
la $sp, 8($sp) # (restore stack pointer)
jr $ra # return
# END EPILOGUE ####################################
I can think of hack-y ways to fix it after the fact, but is there a better way that I should be doing this?

Related

Mips: going back to incorrect return address

I have a mini bank program written that goes calls multiple functions inside the subrouting deposit, this is the subroutine
deposit:
addi $sp, $sp, -8 #save space on stack
addi $s3, $0, 1 #trigger s3
sw $s3, 0($sp)
sw $ra, 4($sp)
.....
jal AsciiConvert #convert ascii of deposited amount to integer
beq $v0, $0, Err_ACC #if no value to be deposited was inputed print error message
beq $t0, $0, deposit_checking #if check exists returns a 0
beq $t0, 1, deposit_saving #if check exists returns a 1
jal printarray
lw $s3, 0($sp)
lw $ra, 4($sp) # reload $ra so we can return to caller
addi $sp, $sp, 8 # restore $sp, freeing the allocated space
jr $ra
deposit_checking:
... arithmetic operations...
jr $ra
the ascii convert subroutine:
AsciiConvert:
...normal arithemtics...
j ConvertOP
ConvertOP:
lb $s0, 0($a1)
beq $s0, $0, endConvert #end at null terminating
beq $s0,32,endConvert #if found a space
addi $s0, $s0, -48 #convert to int
mul $s2, $s1, 10 #multiply sum by 10
add $s2, $s2, $s0 #sum = sum + previous number
add $s1, $s2, $0 #s1 holds previous value
addi $a1, $a1, 1 #increment adress
add $v0, $s2, $0 #store the number in the return adress
j ConvertOP
endConvert:
jr $ra
When I go into deposit, I jal AsciiConvert and then I go into the deposit_Checking subroutine, however the return address of that deposit_Checking returns me back to the line of jal AsciiConvert and not to the line where I called the deposit_Checking subroutine, leading to an infinite loop between Ascii convert subroutine and deposit_Checking subroutine...can someone please help me?
deposit_checking looks like a subroutine, and you identify it as a subroutine in your post, but, we don't enter subroutines with beq instruction, you're supposed to use jal to call a subroutine.
In machine code, the return address, $ra for MIPS, is effectively a parameter to the subroutine — it tells the subroutine where to resume execution in the caller, where to return to.  There are several ways to set the $ra register with a meaningful return address, though of course jal is by far the most common way.
beq transfers control of the processor to the target label (when eq is true) by changing the program counter (pc) though does not provide a (new) $ra value.
By not setting $ra to a new value, its old value is retained.  Since the $ra register was last set by the jal AsciiConvert, the jr $ra for the other function goes back there, none the wiser that this was not the right call — as it is the caller's job to set that parameter properly.
And while some instruction sets allow calling on a condition, we wouldn't necessarily want all beqs to capture a return address, because then any function that used beq would have to concern itself with preserving $ra.
Let's also note that these behaviors are all visible during debugging.  jr $ra, for example will transfer control to whatever machine instruction is addressed by the value in the $ra register.  When you first enter a subroutine/function, there should be a proper return address parameter provided in $ra register, and by the time you get to the end of the function with its final instruction jr $ra, if the value in the $ra register's value has changed from entry, then it won't go back to where it was called from — so we'd be looking for somewhere in between that changes $ra, without restoring it back.

Converting floating point numbers to integers without conversion instructions

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

MIPS- How to Subtract (already used sub- does not work!)

My code comes up with Unsupported R-Type, how do I make it subtract correctly. Tried changing other details within.... Already tried using subu...............................................................................................
.data
str: .asciiz "\nHello World!\n"
# You can change what is between the quotes if you like
.text
.globl main
main:
# Do the addition
# For this, we first need to put the values
# to add into registers ($t0 and $t1)
li $t0, 30 # You can change the 10
li $t1, 20 # You can change the 20
# Now we can add the values in $t0
# and $t1, putting the result in special register $a0
sub $a0, $t0, $t1
# Set up for printing the value in $a0.
# A 1 in $v0 means we want to print an int
li $v0, 1
# The system call looks at what is in $v0
# and $a0, and knows to print what is in $a0
syscall
# Now we want to print Hello World
# So we load the (address of the) string into $a0
la $a0, str
# And put a 4 in $v0 to mean print a string
li $v0, 4
# And just like before syscall looks at
# $v0 and $a0 and knows to print the string
syscall
# Nicely end the program
li $v0, 0
jr $ra
Your program runs fine in the mars and spim simulators except for program termination. These simulators don't set up $ra, so it's zero. So, at the end, you're returning to something that may have semi-random instructions, including an illegal one. Thus, it's not your sub at all that is the problem. It's what happens later.
Change:
# Nicely end the program
li $v0, 0
jr $ra
Into:
# Nicely end the program
li $v0, 10
syscall

In MIPS, how to use syscall 14 to read through a long file?

I am currently working on a project (using MARS) where I need to read a multi-line file using syscall 14. I have a set buffer-length that I am using for the syscall that is 80-bytes long. I have set up my loop within a _readLine function so that the contents of the buffer should be printed to the console with each iteration. This is how I realized that my loop only reads the first 80-bytes of a file, and nothing more.
I've been scouring the internet trying to find a hint on why I can't read the next 80-bytes of the file. I thought it might have something to do with the file descriptor, but when I tried incrementing it, nothing changed, and it was still only outputting the first 80-bytes of the file with syscall 14.
Can someone please help me figure out what is wrong, or give me an idea as how to point to the next 80 bytes of my file? My code is below (fileBuff holds the address of a user-inputted file name, and _printBuffer is a function I use later in my program but you can ignore).
main:
# Open file for reading
addi $v0, $zero, 13
la $a0, fileBuff
add $a1, $zero, $zero # pass in flags
add $a2, $zero, $zero # pass in mode
syscall # open a file (file descriptor returned in $v0)
add $s6, $zero, $v0 # store descriptor in $a0
jal _readLine # call _readFile function
jal _printBuffer
addi $v0, $zero, 10 # prepare to exit the program
syscall # exit
_readLine:
readLoop:
add $a0, $zero, $s6 # setup file descriptor
la $a1, buffer # address of buffer
addi $a2, $zero, 80 # read 80 bytes
addi $v0, $zero, 14 # read from the file (descriptor already in $a0, buffer address in $a1, buffer length in $a2)
syscall # write to the file
beq $v0, $zero, doneReading
slt $t0, $v0, $zero # if end of file, then close file
beq $t0, 1, doneReading # if error, then close file
la $t0, buffer # load buffer address into $t0
add $s6, $zero, $v0 # save file length in $s0
add $s6, $s6, $t0 # change descriptor to where last left off in the file
#### remove... eventually
addi $v0, $zero, 4
la $a0, buffer
syscall
####
j readLoop
doneReading:
addi $v0, $zero, 16 # syscall to close the file
add $a0, $zero, $s6 # file descriptor to close
syscall # close the file
jr $ra
Syscall 14 reads in a continuous string.
When you tell it to read 80-bytes, it will read 80 bytes.
When you call it again (without closing it), it will read the next 80 bytes and so on.
So I suggest you move this block of code:
addi $v0, $zero, 16 # syscall to close the file
add $a0, $zero, $s6 # file descriptor to close
syscall # close the file
into your main block right before the system exit call.

Passing Arguments: MIPS

I'd like to pass a character as an argument to a function in MIPS. Do I do this by storing the character into register $a0, use jal to move to the function, then extract what's in $a0 into a separate register using lw?
If someone could give me an example of passing an argument or two in MIPS, I'd really appreciate it. I've found a lot of info on the MIPS calling conventions, but not any simple and succinct examples.
No need to use lw which is for extracting words from memory. You can simply use $a0 in the sub-routine.
Take a look at this example of a "print-char" function:
.text
main:
#save $ra on stack
addi $sp $sp -4
sw $fp 0($sp)
move $fp $sp
addi $sp $sp -4
sw $ra -4($fp)
#call sub-routine
addi $a0 $zero 'A'
jal printchar
#restore and shrink stack
lw $ra -4($fp)
lw $fp 0($fp)
addi $sp $sp 8
jr $ra
#prints a char and then a new line
printchar:
#call print-char syscall
addi $v0 $zero 11
syscall
addi $a0 $zero 10
syscall
jr $ra
As demonstrated, you the value of the $a0 register is just used in the sub-routine as it returns the value that it was given before the jal.
Also demonstrated is proper expansion and shrinking of the stack as is necessary for calling a sub-routing. As you will notice, the sub-routine does not perform this operation as it does not call a sub-routine and there-fore does not need to save the $ra. Stack manipulations would also be required in the sub-routine if it were to use an $s register as the MIPS calling convention specifies these as callee saved.
a very easy way to go about it would be to load the argument in a temp register and then just use:
move $a0,$t0
this way the argument stored in the temp register will be given as an argument