# 6.4: Methods of Accessing Memory

• • Charles W. Kann III
• Adjunct Professor (Computer Science) at Gettysburg College

The addressing mechanisms for the lw and sw operators shown above are very flexible, and can be used in a number of different ways. These different addressing mechanisms will all prove useful in retrieving memory values. Four methods of addressing data will be shown here, which will be called addressing by label, register direct, register indirect, and register offset, and memory indirect21 (or just indirect).

Different ways of storing data will lend themselves to different mechanisms to access the data. For example, it will be natural for stack data to use register offset addressing, and natural for array processing to use register direct addressing. Addressing by label will be the one with that initially most readers will be most comfortable with, but will by far be the least useful. It is presented mostly to aid readers comfort level.

To illustrate accessing of memory, the following quadratic calculation program from chapter 2 is used. It implements the equation ax2+bx+c based on the value of the user input of x, and prints the result. In the examples in the next 3 sections, the constants a=5, b=2, and c=3 will be stored in the data segment, and 3 different memory access methods shown to retrieve them. The pseudo code for this example follows. Note that the use of the volatile keyword tells the programmer that the variable a, b, and c must be stored in memory, and cannot be immediate values. The static keyword tells the program that the memory to be used should be in the data segment.

Program 6-1: Quadratic program pseudo code

main
{
static volatile int a = 5;
static volatile int b = 2;
static volatile int c = 3;
int x = prompt("Enter a value for x: ");
int y = a * x * x + b * x + c;
print("The result is: " + y);
}


Sometimes the address of a variable is known, and a label can be defined for its address. This type of data can only exist in the .data segment of the program, which means that this data cannot move or change size. This is often true of program constants, as is the case here. When the variable is stored in the data segment, it can generally be addressed directly using a label.
In the following implementation of the quadratic calculation program the constants a, b, and c will be loaded from memory using the lw operator with labels. This is very similar to how programmers are used to accessing variables using their label as a variable name. However be warned that what is being accessed is not the equivalent of a HLL variable or constant, as will become readily apparent throughout the rest of this text.

Program 6-2: Accessing memory variables by label

.text
.globl main
main:
# Get input value and store it in $s0 la$a0, prompt
jal PromptInt
move $s0,$v0

# Load constants a, b, and c into registers
lw $t5, a lw$t6, b
lw $t7, c # Calculate the result of y=a*x*x + b * x + c and store it. mul$t0, $s0,$s0
mul $t0,$t0, $t5 mul$t1, $s0,$t6
add $t0,$t0, $t1 add$s1, $t0,$t7

# Store the result from $s1 to y. sw$s1, y

# Print output from memory y
la $a0, result lw$a1, y
jal PrintInt
jal PrintNewLine

#Exit program
jal Exit

.data
a: .word 5
b: .word 2
c: .word 3
y: .word 0
prompt: .asciiz "Enter a value for x: "
result: .asciiz "The result is: "
.include "utils.asm"


## 6.4.2 Register direct access

Register direct access violates the volatile keyword in the pseudo code (as did the use of immediate values), but is included here to show the difference between register direct access and register indirect addressing. In register direct access, the values are stored directly in the registers, and so memory is not accessed at all. The following program shows register direct access.

Program 6-3: Register Direct Access

.text
.globl main
main:
# Get input value and store it in $s0 la$a0, prompt
jal PromptInt
move $s0,$v0

# Load constants a, b, and c into registers
li $t5, 5 li$t6, 2
li $t7, 3 # Calculate the result of y=a*x*x + b * x + c and store it. mul$t0, $s0,$s0
mul $t0,$t0, $t5 mul$t1, $s0,$t6
add $t0,$t0, $t1 add$s1, $t0,$t7

# Print output from memory y
la $a0, result move$a1, $s1 jal PrintInt jal PrintNewLine #Exit program jal Exit .data y: .word 0 prompt: .asciiz "Enter a value for x: " result: .asciiz "The result is: " .include "utils.asm"  ## 6.4.3 Register indirect access Register indirect access differs from register direct access in that the register does not contain the value to use in the calculation, but contains the address in memory of the value to be used. To see this, consider the following example. If the .data segment in this program is the first .data segment that the assembler has encountered, the numbering of variables in this segment begins at 0x10010000, so the variable a will be at that address. The next allocation that the assembler will find is for the variable b. Since the variable a took up 4 bytes of memory, the variable b will be at memory address 0x10010000 + 0x4 = 0x10010004. Likewise variable c will be at memory location 0x10010000 + 0x8 = 0x10010008, and variable y will be at 0x10010000 + 0xc = 0x1001000c. This next program illustrates how register indirect addressing works. Program 6-4: Register Indirect Access .text .globl main main: # Get input value and store it in$s0
la $a0, prompt jal PromptInt move$s0, $v0 # Load constants a, b, and c into registers lui$t0, 0x1001
lw $t5, 0($t0)
addi $t0,$t0, 4
lw $t6, 0($t0)
addi $t0,$t0, 4
lw $t7, 0($t0)

# Calculate the result of y=a*x*x + b * x + c and store it. mul $t0,$s0, $s0 mul$t0, $t0,$t5
mul $t1,$s0, $t6 add$t0, $t0,$t1
add $s1,$t0, $t7 # Print output from memory y la$a0, result
move $a1,$s1
jal PrintInt
jal PrintNewLine

#Exit program
jal Exit
.data
.word 5
.word 2
.word 3
y:  .word 0
prompt: .asciiz "Enter a value for x: "
result: .asciiz "The result is: "
.include "utils.asm"


## 6.4.4 Register offset access

In the lw instruction, the immediate value is a distance from the address in the register to the value to be loaded. In the register indirect access, this immediate was always zero as the register contained the actual address of the memory value to be loaded. In this example, the value will be used to specify how far in memory the value to be loaded is from the address in the register. Again we will make use of the fact that the variable b is stored 4 bytes from the variable a, and the variable c is stored 8 bytes from the variable a.

Program 6-5: Register offset access

.text
.globl main
main:
# Get input value and store it in $s0 la$a0, prompt
jal PromptInt
move $s0,$v0

# Load constants a, b, and c into registers
lui $t0, 0x1001 lw$t5, 0($t0) lw$t6, 4($t0) lw$t7, 8($t0) # Calculate the result of y=a*x*x + b * x + c and store it. mul$t0, $s0,$s0
mul $t0,$t0, $t5 mul$t1, $s0,$t6
add $t0,$t0, $t1 add$s1, $t0,$t7

# Print output from memory y
la $a0, result move$a1, $s1 jal PrintInt jal PrintNewLine #Exit program jal Exit .data .word 5 .word 2 .word 3 y: .word 0 prompt: .asciiz "Enter a value for x: " result: .asciiz "The result is: " .include "utils.asm"  If a register can contain the address of a variable in memory, by extension it seems reasonable that a memory value can contain a reference to another variable at another spot in memory. This is indeed true, and this is a very common way to access data and structures. These variables are called pointer variables, and exist in the compiled executables for all programming languages. However most modern programming languages prohibit the programmer from accessing these pointer variables directly, mainly because experience with languages that allowed access to these variables has shown that most programmers do not really understand them, or the implications of using them. Accessing these pointer variables is always unsafe, and the improper use of pointers has resulted in many of the worst bugs that many programmers have encountered. Having warned against the use of pointer variables in a HLL, there is no way to avoid their use in assembly. Assembly programmers must understand how these variables work, and how to safely use them. The following program shows the use of memory indirect (pointer) variables. The memory at the start of the .data segment (0x10010000) contains an address (or reference22) to the actual storage location for the constants a, b, and c. These variables are then accessed by loading the address in memory into a register, and using that address to locate the constants. .text .globl main main: # Get input value and store it in$s0
la $a0, prompt jal PromptInt move$s0, $v0 # Load constants a, b, and c into registers lui$t0, 0x1001
lw $t0, 0($t0)
lw $t5, 0($t0)
lw $t6, 4($t0)
lw $t7, 8($t0)

# Calculate the result of y=a*x*x + b * x + c and store it.
mul $t0,$s0, $s0 mul$t0, $t0,$t5
mul $t1,$s0, $t6 add$t0, $t0,$t1
add $s1,$t0, $t7 # Print output from memory y la$a0, result
move $a1,$s1
jal PrintInt
jal PrintNewLine

#Exit program
jal Exit

.data
.word constants
y: .word 0
prompt: .asciiz "Enter a value for x: "
result: .asciiz "The result is: "
constants:
.word 5
.word 2
.word 3
.include "utils.asm"


21 For programmers unfamiliar with languages that include pointer variables, such as C/C++, the concept of indirect addressing is confusing and it is hard to justify why it would be used. Indirect addressing is included here because it is an important topic, but no justification of why it is used will be provided.

22 Pointer variables, addresses, and references have largely the same meaning. In MIPS assembly, a reference is a pointer. However there are cases, such as accessing distributed data in a HLL (such as using Java RMI) where a reference could have some different semantics. So the terms pointer variables and addresses are generally called references in HLL, though in most cases they are the same thing.