MIPS Assembly File Writing - mips

I am trying to write to a file in MIPS assembly and it seems that I cannot get it to work. The code is straightforward, but the $v0 register returns -1 no matter what I type. I have tried other people's code and still end up getting the same results.
The code:
filename: .asciiz "file.txt"
buffer: .asciiz "hello textual world"
.text
open_file:
li $v0, 13 # open file
la $a0, filename # file name
li $a1, 1 # write flag
li $a2, 0 # ignore mode
syscall
jal print
write_to_file:
move $a0, $v0 # descriptor
li $v0, 15 # write to file
la $a1, buffer # buffer
li $a2, 20 # max chars to write
syscall
jal print
close_file:
li $v0, 16 # close
# move $a0, $v0 # descriptor
syscall
jal print
li $v0, 10 # exit program
syscall
print:
move $a0, $v0
li $v0, 1
syscall # print v0
li $v0, 11
li $a0, '\n'
syscall # print '\n'
jr $ra
The output:
-1
-1
16
-- program is finished running --
A Screenshot of the Mars dir. Note: I know that the dir contains "FILES.txt" rather than the "file.txt" one. However, I am trying to create a new file.
EDIT:
After some time I ran the program and solved the issue. For some reason, the first syscall did not return -1 when I ran it today, but the problem was that in "jal print", $v0 changed its value, which means that the line that follows it, first line of write_to_file label, loads an incorrect descriptor to $a0. Another potential problem is that I put 20 characters to print instead of 19.
Long story short, I've saved the file descriptor in $s0 and put 19 characters to be written and now the program works.

Related

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

Assembly MIPS - Create a file, specific extension

I am coding a program in asm, I know a bit, but no expert. I am using Mars emulator. The part I do not understand is how does one create a file and make it have an specific extension like, file.vig? What I want is to create a file, give a name I want, write to it. None of this worked so far. I have the rest of the program working, but not this file creation and modification while in run time of Mars.
res points to a string
FileName points to a string like: file.vig
li $v0, 13 # system call for open file
la $a0, FileName # output file name
li $a1, 577 # Open for writing (flags are 0: read, 1: write)
li $a2, 0x1ff # was recommended for file permissions
syscall # open a file (file descriptor returned in $v0)
move $s6, $v0 # save the file descriptor
# Write to file just opened
li $v0, 15 # system call for write to file
move $a0, $s6 # file descriptor
la $a1, res # address of buffer from which to write
li $a2, 15 # hardcoded buffer length
syscall
move $a0, $s6
li $v0, 16 # close
syscall
li $v0, 10
syscall
You didn't check the return value from your open syscall. It was returning -1 because you were loading $a1 with 577 and not 1 [it's not quite like libc and is finicky about this value].
Here's your program, slightly adjusted to demo this and retry the open with the correct options [please pardon the gratuitous style cleanup]:
.data
FileName: .asciiz "file.vig"
bad_msg: .asciiz "open syscall failed\n"
ok_msg: .asciiz "open was okay\n"
res: .byte 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
.text
.globl main
main:
li $a1,577 # Open for writing (flags are 0: read, 1: write)
li $a2,0x1ff # was recommended for file permissions
main_retry:
li $v0,13 # system call for open file
la $a0,FileName # output file name
syscall # open a file (descriptor returned in $v0)
move $s6,$v0 # save the file descriptor
bltz $s6,main_fail # did open fail? fly if yes
la $a0,ok_msg
li $v0,4
syscall
# Write to file just opened
li $v0,15 # system call for write to file
move $a0,$s6 # file descriptor
la $a1,res # address of buffer from which to write
li $a2,15 # hardcoded buffer length
syscall
move $a0,$s6
li $v0,16 # close
syscall
main_exit:
li $v0,10
syscall
main_fail:
la $a0,bad_msg
li $v0,4
syscall
li $a1,1 # correct write mode (O_WRONLY)
li $a2,0 # file permissions are ignored by mars
j main_retry

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.

opening binary file for reading

I'm trying to open binary file for reading in mars mips simulator:
.data
file: .asciiz "o.bmp"
.text
li $v0, 13
la $a0, file
li $a1, 0
li $a2, 0
syscall #file descriptor of oepened file in v0
beq $v0, -1, end #my program every time jumps to end so sth is wrong
solution:
file mars.jar (or other name of mars program) must be in the same directory with file "o.bmp"

Need help with MIPS program

I'm working on a mips program that will run on pcspim and i need a little help. The description of the program is: Write a program that reads a string (from a keyboard), stores it in the memory, and computes and prints the frequency of each character; and then it reverses the string and prints the reversed string.
so far i have is...
.data # Data declaration section
userString: .space 256
Prompt: .asciiz "\nEnter a word: "
newLine: .asciiz "\n"
.text
main: # Start of code section
li $v0, 4
la $a0, Prompt
syscall
li $v0, 8
la $a0, userString
li $a1, 256
syscall
jr $ra
la $a0, userString
move $t0, $a0
lb $t1, 0($t0)
li $v0, 4
move $a0, $t1
syscall # prints first letter of word
Right now i just wanted to see if i've actually stored the input into the userString array. So at the end i tried to print out the first letter. but it doesnt seem to be printing anything.
Any suggestion?
thank.
I've broken your code down into three parts: prompting, input, display. I assume the first two parts were given to you and the third is what you are focusing on right now. I'll explain what the first to parts are doing then explain what the third is doing right now and what you probably want it to do at this point.
.data # Data declaration section
userString: .space 256
Prompt: .asciiz "\nEnter a word: "
newLine: .asciiz "\n"
.text
# Part I
main: # Start of code section
li $v0, 4
la $a0, Prompt
syscall
# Part II
li $v0, 8
la $a0, userString
li $a1, 256
syscall
jr $ra
# Part III
la $a0, userString
move $t0, $a0
lb $t1, 0($t0)
li $v0, 4
move $a0, $t1
syscall # prints first letter of word
Part I
This is pretty straightforward, when we start executing the program counter will be set to the address of the main label. It loads the value 4 into $v0 (that seems to be the print string system call number), and then loads the address of the Prompt string into the first argument register $a0. The last bit just performs the system call that puts the string on the screen.
Part II
Now that the "Enter a word: " string has been printed on screen, we want to actually read what the user is typing. It looks like here we're using system call #8 (probably read string), so we load that value into $v0 in preparation for the syscall. Then, since we want to read the user string into userString, we load the address of that label into $a0 (the first argument for the read string function) then, since we are savvy programmers, we give the upper bound of how many bytes userString can hold (256) in $a1. Then we perform the system call, you type in a string at the keyboard and hit enter and we return to the next line of code.
That line is jr $ra, which means "jump to the location stored in register $ra (return address)". You probably don't want this, because it marks the end of the main function and likely you program exits back to the command line at this point, probably best to remove it.
Part III
Again, you're loading the address of userString into $a0 (and also moving it into $t0 in the next line). Now it gets weird, you load the first byte 0($t0) of userString into $t1. This is a ASCII character value (like 72 or something). Then you start up the system call stuff again with the print string system call (#4) and the argument of $t1. Which you think will print the first letter of the word, which I disagree with. Here's why. If the user types the string, "Hello, world!" this is what it looks like in memory:
userString: H e l l o , w o r l d !
offset: 0 1 2 3 4 5 6 7 8 9 10 11 12
So, loading 0($t0) moves the letter H into register $t1, then when you perform the system call it tries to print the string starting at H to the screen. However, there is not a string starting at letter H, it starts at the address of userString. So if you just move the address of userString into register $a0, then do system call #4 it should print userString to the screen.
#mjshultz
i've changed it up a little. Didnt think i needed 2 loops. Also i've increment it by four because i thought each character is 4 bytes so to go to the next letter i need to increment the offset by four.
.data # Data declaration section
userString: .space 256
Prompt: .asciiz "\nEnter a word: "
newSpace: .asciiz " "
newLine: .asciiz "\n"
.text
main: # Start of code section
li $v0, 4
la $a0, Prompt
syscall
la $a0, userString
li $a1, 256
li $v0, 8
syscall
la $a0, userString
move $s0, $a0
loop:
lb $t1, 0($s0)
li $v0, 1
move $a0, $t1
syscall
li $v0, 4
la $a0, newSpace
syscall
addi $s0, $s0, 4
blt $s0, 256, loop