Understanding opening and reading a file in assembly - file

I've got a project for a class in which we have to transform a picture using sobel operators in assembly, and I'm having a bit of a problem understanding some example code.
In the data segment and in the main function is everything that's need to make the function work (The code works, I just don't understand why).
The bit I don't understand is the use of the li command to change the values of the $aregisters.
read_rgb_image:
# Place file and size in register,
move $s0, $a0 #file name
move $s1, $a1 #buffer
move $s2, $a2 #buffersize
# Open file
move $a0, $s0 # File's directory/name
li $a1, 0 #THIS LI ARE THE COMMANDS I DON'T UNDERSTAND
li $a2, 0 # Read life
li $v0, 13 # Option for opening file
syscall
# Read file
move $a0, $v0 # File descriptor
move $a1, $s1 # Buffer with result
move $a2, $s2 # Space of information to read
li $v0, 14 # Read file
syscall
# Store read buffer
move $s1, $v0
# Close file
li $v0, 16 # Close file
syscall
# Return
move $v0, $s1 # Make return
jr $ra
nop
Can somebody please explain this to me?!

The LI instruction loads an numeric value into a register. Before you make a system call, you need to load the $v0 register with the number assigned to the system service. You also need to load argument registers with system service specific parameters. Without the documentation, we can only guess (beyond the comments in the code) why the specific values being loaded into the registers. However, that is what is going on.
We can guess that you are calling the 4-paremeter version of the open function and that your specifing the file name, mode=0, and flags=0 using the argument registers.

MIPS defines pseudoinstructions that are not actually part
of the instruction set but are commonly used by programmers and compilers.
load immediate li is a pseudoinstruction it loads a 32-bit constant using a combination of lui and ori instructions.
The following instructions are equivalent.
MIPS instruction
lui $s0, 0x1234
ori $s0, 0xAA77
pseudoinstruction
li $s0, 0x1234AA77

Related

Quicksort from C to MIPS - How to pass parameters and maintaining variables for stack frame?

I am creating a Quicksort algorithm on an array of integers. I am using this C algorithm and translating it into MIPS. However, MIPS and recursion is very tough indeed.
I am unsure how to send parameters into the recursive call QS. I recently discovered that I can change my $s registers for each frame in the call stack, by moving the stack pointer 4 bytes. This will allow me to change the $s registers for each stack frame such that I don't need a million variables for each QS frame.
My problem is that I don't really understand how and when to set and get these $sx values during recursion.
Recursion is implemented by moving the stack pointer register ($sp).
First of all, let's understand the point of moving the stack pointer:
When you use recursion in a high level language, what it does, basically, is to "save" the state of the current function call in the "stack memory".
To achieve this, you will have to:
Save the current state of your program (all the variables/registers
you are using within the scope of the "function"), in the stack memory;
Call the function "recursively" (which might modify all the registers you were using);
When the function finishes, you have to restore the previous state and "free" the space you allocated.
But besides that, we have to save the value of $ra, to keep track of where we're supposed to go when the upper function ends.
Here's a simple example of a program that calculates factorial(n) recursively:
.text
main:
# Calls Fact with Input ($a0) N = 10
li $a0, 10
jal fact
# prints the Output ($v0) Factorial(N)
move $a0, $v0
li $v0, 1
syscall
# exit
li $v0, 10
syscall
# Input: $a0 - N
# Output: $v0 - Factorial(N)
fact:
# Fact(0) = 1
beq $a0, 0, r_one
# Fact(N) = N * Fact(N-1) use recursion
# allocate 8 bytes in the stack for storing N, and $ra
addi $sp, $sp, -8
# stores N in the first, and $ra in the last position
sw $a0, 4($sp)
sw $ra, 0($sp)
# call Fact(N-1)
addi $a0, $a0, -1
jal fact
# Restore the values of N and $ra
lw $a0, 4($sp)
lw $ra, 0($sp)
# Free the 8 bytes used
addi $sp, $sp, 8
# Set the return value to be N * Fact(N-1) and return
mul $v0, $a0, $v0
jr $ra
# return 1;
r_one:
li $v0, 1
jr $ra
This is what you should keep in mind when implementing your code, basically.
Just pay attention to:
The stack pointer is decremented;
How many bytes you need to allocate. In this example I use 2 32-bits integers, 8 bytes in total. It will deppend on how many variables you need to store, and their size.
How to access them with lw and sw, using the correct index. Also, be aware of memory alignment;
This does not only apply for recursion. You can use the stack memory to call another function that uses registers that are being used (basically the same thing as recursion, except that you don't need to save $ra). And also store an array, a struct, etc.
Edit:
Some considerations:
The right place to do that is where your code calls the function (allocate and save), and after this call (restore and free).
Understand your code to know which variables need to be saved (might be used).

How to get the address of an array and save it to a register in assembly?

I want to save the memory address of A[ ] in a register, say $a0 because I will pass this as an argument to a procedure even though I can reach A in any scope of the program.
In the code, the reason I used sb instead of sw is there is an allignment problem when I assemble it.
When I say lb $a0, A it stores 4 to $a0, which is the value not the address.
.data
A: .space 16
.globl main
main:
# Initialize values in the array
addi $s0, $zero, 4
addi $s1, $zero, 8
addi $s2, $zero, 3
addi $s3, $zero, 5
# This $t0 is just used for indexing while inserting to A
addi $t0, $zero, 0
sb $s0, A($t0)
addi $t0, $t0, 4
sb $s1, A($t0)
addi $t0, $t0, 4
sb $s2, A($t0)
addi $t0, $t0, 4
sb $s3, A($t0)
li $t0, 0
Use the la pseudo-instruction. la $t0, A.
If A doesn't fit in 16 bits, this will assemble to a sequence like
lui $t0, high16(A) ; ori $t0, $zero, low16(A). See this basic MIPS instruction-set reference for LUI. Your assembler may use addui instead of ori; I think some assemblers have an option for which to choose for li / la pseudo-instructions.
There's also an li pseudo-instruction (for load-immediate) for use with numeric constants instead of addresses, but it works identically.
For the alignment problem, try making sure A's address is word-aligned. I would have thought this would happen automatically, but maybe you left out a .asciz string constant earlier in .data from the code you posted? Anyway, either put A first before non-multiple-of-4 sized objects, or use a .align directive to pad to the next multiple of 4.
.data
.align 4 # align by 4 bytes.
A: .space 16
If A's address fits in 16 bits, you don't need it or the offset in a register, just use sb $s0, A+4($zero) and so on. (But if you're using sb / lb, then why still offset by 4 bytes between elements? Why not make it a 4-byte long array of 4 bytes?)
.globl main
main:
# Initialize values in the array
li $t0, 4
sw $t0, A($zero)
addui $t0, $zero, 8 # doing it manually without an LI pseudo-instruction
sw $t0, A+4($zero)
li $t0, 3
sw $t0, A+8($zero)
li $t0, 5
sw $t0, A+12($zero)
#li $t0, 0
You don't need to use a different register every time, although I guess without register-renaming a classic-RISC pipeline might stall for a Write-After-Read hazard (WAR) when li tried to write t0 before the previous sw had read it. On a superscalar CPU, it makes sense to mix different instruction types (ALU addui and memory sw) so they can execute in parallel instead of maybe waiting longer than necessary before the first store executes.
Also, this is arguably more human readable because the value and address go together.

Read File into an Array? - MIPS

I'm not sure exactly how to tackle this, but I need to code a function that takes in an address for the start of an array, address of a file name, and the maximum number for bytes to read. I'm not even sure if my code works or not, but this is what I have, I just don't think this is reading in the values into an array form. If someone can clarify what exactly syscall 14 does, i'd appreciate it.
fill_the_array:
la $t0, 0($a0) #base address of the array in memory
la $t1, 0($a1) #address of the filename in memory
move $t2, $a2 # maximum number of bytes to read from the file into memory
#open file
li $v0, 13 #syscall for opening the file
la $a0, 0($t1) #address of file name
li $a1, 0 #read in data
li $a2, 0 #mode is ignored
syscall #open the file descriptor
move $s0, $v0 # file descriptor
move $a0, $s0 # file descriptor
move $a1, $t0 #address into input buffer (the address for the array???)
move $a2, $t2 # maximum number of bytes
li $v0, 14
syscall
#close the file
li $v0, 16
move $a0, $s0
syscall
jr $ra
If someone can clarify what exactly syscall 14 does, i'd appreciate it.
Name Number Arguments Returns
--------------------------------------------------------------------------------------------------------------------------------------
read from file 14 $a0 = file descriptor $v0 contains number of characters read (0 if end-of-file, negative if error).
$a1 = address of input buffer
$a2 = maximum number of characters to read
So it reads a number of bytes (at most $a2 bytes) from a file, and stores them in memory starting at the address given in $a1. The actual number of bytes read is then returned in $v0.
If you need to check whether or not your code works, run it in a simulator like MARS or SPIM. They both have memory viewers. They also let you single-step through your code and set breakpoints, in case your code isn't working as expected and you need to find out where things go wrong.

Mips char array indexing with counter

Overview of program: Input of a number 1-26, give the corresponding Capital letter too the number
My logic: Set up an Array type "structure" using .byte with chars. have a counter going through the array. once the counter is equivenlt to the input number print out the current point at the array.
This is a homework assignment so I'm not trying to "nudge" out the answer but guidance would be very helpful.
This is why where I think its going wrong. When I add 1 to the address it for some reason gives me a error. But when i add 4 it works fine? A char is supposed to take only 1 bit correct? I understand that when indexing address's of ints in an array it should be by 4.
.data
prompt: .asciiz "Enter the value of n here: "
larray: .byte 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
.globl main
.text
main:
la $t1, larray # Loads Array addresss into $t1
li $v0, 4 # System call for Print String
la $a0, prompt # Load address of prompt into $a0
syscall # Print the prompt message
li $v0, 5 # System call code for Read Integer
syscall # Read N into $v0
move $t3, $v0
li $t0, 0 # Loads int 0 into $t0
loop:
beq $t0, $t3, end # Break
lw $a0, ($t1) # Loads current pointer
addi $t0, $t0, 1 # Adds one to $t0 (Counting up +1)
addi $t1, $t1, 1 # Advances to next address in the array
j loop
end:
li $v0, 11 # Print at current index
syscall
li $v0, 10 # return control to system
syscall
I did do research on how to access the char a different way, but I don't think I can implement this way because you would need it hard coded?
Link:
This is the Stack Link that I found
There's no need for the array or the loop. If all you want to do is find the corresponding capital letter for a single number in the range 1-26, this would suffice:
li $v0, 5 # System call code for Read Integer
syscall # Read N into $v0
addiu $v0,$v0,'A'-1 # Convert the number 1-26 to the character 'A'-'Z'
A char is supposed to take only 1 bit correct?
One byte.
When I add 1 to the address it for some reason gives me a error. But when i add 4 it works fine?
You're using the lw instruction, which loads one word (4 bytes). To load a single byte, use the lb or lbu instruction (lb is for signed bytes, lbu for unsigned).

Trying to write a basic main program using a function

I am trying to write a function to copy words from source memory to destination memory.
I have written the function but I am having difficulty executing the code.
It is giving me execption 4 as an error
.data
.text
main:
.setnoreorder
top: beq $a2,0,done
lw $t1,($a0)
sw $t1,($a1)
add $a0,$a0,4
add $a1,$a1,4
j top
sub $a2,$a2,1
done:
jr $ra #return to the main program
add $0, $0, $0 #nop
I want to write a main program which calls this function to copy 800 words from
address 0x50000 to 0x90000 in memory. But when I add the values in $a0-$a2 and run the code it doesnt work.
Does anyone know how to fix it. (I am converting C code to MIPS which is why I have included a C tag
Cheers
.text # code starts here
main: # required label
la $a0,dest # point to destination
la $a1,srce # point to source
li $a2,1000 # move this many words
jal block_copy # call the routine
nop
li $v0,10
syscall
###############################################################################
# block copy - moves $a3 words from $a1 to $a0
#
# register usage:
# $a0 address of destination
# $a1 address of source
# $a2 block size (number of words to move)
# $v0 return code (0 means no troubles)
#
block_copy:
move $v0,$a2 # counter/rc
bc_loop:
lw $t0,0($a1) # no DMA here
sw $t0,0($a0) # we have to move a word at a time
addiu $a0,$a0,4 # point to next word in destination
addiu $a1,$a1,4 # point to next word in source
addiu $v0,$v0,-1 # decrement counter
bgtz $v0,bc_loop # keep on moving if counter is positive
jr $ra # return to caller
###############################################################################
.data
dest:
.word 9:1000 # destination 1000 words (all zeroes)
srce:
.word 0:1000 # source 1000 words (all nines)
Shouldn't that be:
sub $a2,$a2,1
j top
You show a delay slot in two places, here
j top
sub $a2,$a2,1
and here
done:
jr $ra #return to the main program
add $0, $0, $0 #nop
But apparently not here:
top: beq $a2,0,done
lw $t1,($a0)
Maybe the problem is that the load following the beq is, in fact, a delay slot and is being executed even when $a2 is zero (and the branch is taken) - you are loading from memory at ($a0) even when the count is zero - perhaps accessing invalid memory and causing the exception.

Resources