MIPS memory restrictions? - memory

I would like to ask about memory accessing. When I execute a load word command, what memory restrictions exist? Meaning what's the biggest number I can use as offset or base register?
Registers are 32 bits and as far as I know the "immediate" is 16 bits.
Thus, I'm pretty sure I can't do something like
array: .word 0:20000
~
la $s0, array
lw $s1, 15000($s0)
...
So if I want to access the 15000, I might need to la something smaller and go on from there right?
But what's the smaller value I need to access in order to be ok and why?

The immediate field in lw is 16 bits, yes; and it is signed two's complement, so the possible range of immediate offsets is -32768..32767 - so lw $s1, 15000($s0) should be fine.
Realise that la is not a real MIPS instruction. Rather, it directs the assembler to generate the most optimal instruction sequence such that the immediate value you have specified is placed in the specified register. Thus, the full 32 bit range of values may be set using la, but one can generally produce more optimal code by using la once to place a suitable value into some register such that several subsequent instructions are able to use immediate offsets from that value than by using la each time an immediate value is needed.
So, supposing you needed to load values from offsets 40000 and 50000 of your array, you might do:
array: .word 0:20000
~
la $s0, array # get address of array
la $s1, 40000 # get offset into a register
add $s0, $s0, $s1 # add offset to address, i.e. calculate (array+40000)
lw $s1, 0($s0) # fetch data from (array+40000)
lw $s2, 10000($s0) # fetch data from (array+40000+10000)

Related

MIPS Memory Mapped IO received byte causing error

For university, im attemting to use Memory Mapped IO to take in 6 characters store them in a buffer, then print the buffer. The below code i the receiver, $t0 is the adddess of the reciever. It checks if the receiver is ready, if so receives the data. Right now im just attempting to make sure im getting the data. So im attempting to print it, but im receiving a syntax error and I cant work out why.
Reason I think is it might be that the byte received isnt compatible.
lw $t1, 0($t0) # receiver control
andi $t1, $t1,0x0001 # check if ready
beq $t1, $zero,readloop # if not ready
lb $s0, 4($t0) # receiver data
li $v0, 11 # print char
li $a0, $s0 # takes address of string as argument <--- This is where the compiler is saying theres a syntax error
syscall

How do I print a long integer that I have in a register?

I have defined a long integer as follows:
memTotal: .long 0
Then, I am adding to it with something like this:
addl 12(%di), %ecx
Where I then move %ecx to memTotal. My question is, how would I go about calculating the size in MB of the memTotal. I tried something along the lines of:
shrl $20, %eax
But how would I then print that as in int for MB?
Am I on the right track? Any help is appreciated.
I assume you know how to print a single ASCII character. So now you need an algorithm to extract the digits from an integer a - I will provide one that I think is easy to understand and easy to expand (it's not necessarily the best).
calculate b := a%10. b is the last digit of your number
set a := a/10 (integer division)
repeat from beginning to get second-to-last digit, etc. Stop when a == 0.
Once you have the value of a digit, you can add a fixed constant to get its ASCII value, which you can use to print the corresponding character.
The above enables you to print a number. Unfortunately, at this point you can only print it backwards. In order to fix that, allocate a string in which you can put the digits from right to left. Start by allocating a string that will be large enough to hold all long ints, then come up with a modification of the above algorithm that will keep track of how many digits there are, and allocate a string accordingly.
(And yes, shrl $20, %eax sounds sensible for turning bytes into what is usually called MiBs. Conventions vary, but I think the usual one is 1 MB = 10^6 bytes, and 1 MiB = 2^20 bytes.)

MIPS Explanation: sw

The Background
I am currently working on small MIPS program for a homework assignment, and in the process learning some of the language. I am extremely new to this, and as such I am very unsure of myself when it comes to even the most basic aspects of the operations that I'm performing. Furthermore, my instructor insists on not using pseudocode in our assignments, which is leading to a lot of difficulty in understanding how to accomplish certain tasks.
The Assignment
My assignment question is this: Suppose you want to compute iteratively (in a loop) the first 20 Biggie numbers, B(i) = 2i + 17i and store them sequentially in an array B whose base address in MIPS memory is stored in register $s0. Please write the MIPS code (fully commented) to compute B(i), 1 < i < 20.
My Solution
What I currently have:
.globl main
main:
.data
BiggieArray:
.space 80 #4 bytes per word * 20 biggie numbers = 80 bytes reserved
.text
addi $s1, $zero, 1 #$s1 tracks i, initialize i with value of 1
addi $s2, $zero, 21 #$s2 holds 21, for use in comparing with the value of i
addi $s3, $zero, 2 #$s3 holds the value for the first mult
addi $s4, $zero, 17 #$s4 holds the value for the second mult
STARTLOOP:
beq $s1, $s2, ENDLOOP #compares i ($s1) with $s2. If they are equal, i > 20, so branch to the end of the loop.
add $t0, $s1, $s1 #find 2i
add $t0, $t0, $t0 #find 4i, use as offset for BiggieArray
addi $t0, $t0, -4 #adjusts to start from index 0 instead of index 1
mult $s1, $s3 #Calculates 2i
mflo $s5 #$s5 holds 2i
mult $s1, $s4 #Calculates 17i
mflo $s6 #$s6 holds 17i
add $s7, $s5, $s6 #$s7 holds 2i+17i
add $t1, $s0, $t0 #$t1 holds the current address of BiggieArray[i]
sw $t1, 0($s7) #stores the value 2i+17i into RAM ?????
addi $s1, $s1, 1 #increment i
j STARTLOOP
ENDLOOP:
My Question
I realize that I don't currently have $s0 initialized to anything, but that's not what's giving me issues. What I'm confused about is how I would store that value of 2i+17i back into BiggieArray. Any help or very simple explanation of how sw works would be greatly appreciated.
In your example, you have the registers reversed. It should be:
sw $s7, 0($t1) # since s7 holds the value you want to store, and t1 holds the mem address where you want to store it

Can't figure out use of stack in program?

Ok, so my task was to modify this code to count both upper and lower case vowels. The point of the program is to demonstrate the use of stack to preserve data across function calls:
##
## vowel.a - prints out number of vowels in
## - the string str
##
## a0 - points to the string
##
#################################################
# #
# text segment #
# #
#################################################
.text
.globl __start
__start: # execution starts here
la $a0,str
jal vcount # call vcount
move $a0,$v0
li $v0,1
syscall # print answer
la $a0,endl
li $v0,4
syscall # print newline
li $v0,10
syscall # au revoir...
#------------------------------------------------
# vowelp - takes a single character as a
# parameter and returns 1 if the character
# is a (lower case) vowel otherwise return 0.
# a0 - holds character
# v0 - returns 0 or 1
#------------------------------------------------
vowelp: li $v0,0
beq $a0,'a',yes
beq $a0,'e',yes
beq $a0,'i',yes
beq $a0,'o',yes
beq $a0,'u',yes
jr $ra
yes: li $v0,1
jr $ra
#------------------------------------------------
# vcount - use vowelp to count the vowels in a
# string.
# a0 - holds string address
# s0 - holds number of vowels
# v0 - returns number of vowels
#------------------------------------------------
vcount:
sub $sp,$sp,16 # save registers on stack
sw $a0,0($sp)
sw $s0,4($sp)
sw $s1,8($sp)
sw $ra,12($sp)
li $s0,0 # count of vowels
move $s1,$a0 # address of string
nextc: lb $a0,($s1) # get each character
beqz $a0,done # zero marks end
jal vowelp # call vowelp
add $s0,$s0,$v0 # add 0 or 1 to count
add $s1,$s1,1 # move along string
b nextc
done: move $v0,$s0 # use $v0 for result
lw $a0,0($sp) # restore registers
lw $s0,4($sp)
lw $s1,8($sp)
lw $ra,12($sp)
add $sp,$sp,16
jr $ra
#################################################
# #
# data segment #
# #
#################################################
.data
str: .asciiz "long time ago in a galaxy far away"
endl: .asciiz "\n"
##
## end of file vowel.a
my modified code that works:
##
## vowel.a - prints out number of vowels in
## - the string str
##
## a0 - points to the string
##
#################################################
# #
# text segment #
# #
#################################################
.text
.globl __start
__start: # execution starts here
la $a0,str
jal vcount # call vcount
move $a0,$v0
li $v0,1
syscall # print answer
la $a0,endl
li $v0,4
syscall # print newline
move $a0,$t0
li $v0,1
syscall
la $a0,endl
li $v0,4
syscall
li $v0,10
syscall # au revoir...
vowell: li $v0,0
beq $a0,'a',yes
beq $a0,'e',yes
beq $a0,'i',yes
beq $a0,'o',yes
beq $a0,'u',yes
jr $ra
yes: li $v0,1
jr $ra
vowelu:
li $v0,0
beq $a0,'A',yes
beq $a0,'E',yes
beq $a0,'I',yes
beq $a0,'O',yes
beq $a0,'U',yes
jr $ra
vcount:
sub $sp,$sp,20
sw $a0,0($sp)
sw $s0,4($sp)
sw $s1,8($sp)
sw $ra,12($sp)
sw $s2,16($sp)
li $s0,0
li $s2,0
move $s1,$a0
nextc:
lb $a0,($s1)
beqz $a0,done
jal vowell
add $s0,$s0,$v0
jal vowelu
add $s2,$s2,$v0
add $s1,$s1,1
b nextc
done:
move $v0,$s0
move $t0,$s2
lw $a0,0($sp)
lw $s0,4($sp)
lw $s1,8($sp)
lw $ra,12($sp)
lw $s2,16($sp)
add $sp,$sp,20
jr $ra
.data
str: .asciiz "Long Time Ago in a Galaxy Far Far Away"
endl: .asciiz "\n"
I don't understand what the lw block at the end is for. The program stores the count in s0 and t0 respectively, so whats the point? It looks as though its just restoring the original values at the end. Whoop de do was that there just to demonstrate that its possible?
I don't know much about MIPS, but I'm assuming that the idea is similar to x86.
Just from what you said, the last LW is restoring the original values. The reason this occurs is so you can call a function inside of another function (inception style) and not worry about losing variables and values placed on the stack that weren't allocated to memory (things like iterators etc).
For example, lets say you're iterating through a whole page of text taking it one line at a time. You'll store the iterator of the outer loop (the page line) in a register. Now when you enter the function to count the number of vowels, you don't want to worry about losing that value so it gets pushed onto the stack. Your vowel counter will run do what it's supposed to do, use whatever registers it wants, and then when it completes it will (depending on your methodology) restore the values from the stack to their original places. That way the inner function doesn't mess with the outer function and you don't have your registers getting smashed by the called method's functions.
I'm not familiar with MIPS assembly, but in general each platform has conventions as to how subroutines are supposed to behave. One of those conventions is usually around which CPU registers a subroutine must preserve. The conventions, taken together, form the ABI.
Think of it this way: When you have a program with only a few subroutines, its easy enough to keep track of "yeah, this routine destroys register X" each time you call it. But as your program grows, that becomes very difficult. Imagine the difficulty of changing a function to use a new register—you'd have to then check each subroutine that calls this routine, to make sure it doesn't rely on the register across the call. And every routine that calls those routines, etc. Change a commonly-used utility function, and you wind up having to verify the entire program; in this way lies madness.
There are two maintainable solutions to this: either the caller saves all registers it is using, or the callee saves all registers it changes. Normally, you'd expect code to get less complex (and use less registers) the further in the call chain you get, so the callee probably has a smaller set to save. Further, the number of function calls normally exceeds the number of functions, so callee saving also produces less code. It looks like MIPS follows this logic, and requires the callee to save the registers. Sometimes, on architectures with a lot of registers (e.g., PowerPC) there are some which are considered "temporary" and thus the callee doesn't have to save them; this is a combination of the two approaches.
In the most common MIPS calling convention
the temporary registers $t0,$t1,...,$t9 can be destroyed (i.e. changed and not restored) when you call a function.
the $s0,$s1,...,$s7 (callee saved) registers must remain unchanged after you call a function. The function you call will typically store the value of the callee saved registers on the stack if it needs to use these registers. The callee saved registers will be restored from the stack right before the function returns.

How to print .word value that is in the memory in Assembly without using la/li

How do I print .word value that is in the memory in Assembly without using la/li? I can only use the basic functions. I can print .asciiz, but I don't know what I am doing wrong that it is not printing the values (integer) in the memory addresses :(
Here is my code for printing out my asciiz:
lui $a0, 0x1001
addi $a0, $a0, 12 # set the address to my string location
addi $v0, $0, 4
syscall
I wrote the same code except with different addresses but it is not printing out anything. I also tried to search but couldn't find exact answer to this question.
Please advise. Any help will be greatly appreciated. Please correct me if I have misunderstood anything. Thank you in advance.
There are a couple of errors in your code.
First, if you want to print an integer you should use syscall #1 instead of #4
Then, if you want to print an integer which is stored on memory, you have to load that word from memory.
Your code should look something like this:
lw $a0, 0x100C # Load the contents of word stored at address 0x1000 + 12
addi $v0, $0, 1 # Set service #1 (which prints an integer)
syscall # Do the system call

Resources