0% found this document useful (0 votes)
27 views20 pages

CSCE 5610 Computer System Architecture: Content

The document provides an overview of MIPS instruction set architecture (ISA) and its application in assembly language and machine organization. It covers essential concepts such as arithmetic operations, memory management, and control flow instructions, emphasizing the importance of registers and memory in MIPS programming. Additionally, it includes examples of translating C code to MIPS assembly and discusses the significance of pseudo-instructions for simplifying coding tasks.

Uploaded by

x6ycdqdpj6
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views20 pages

CSCE 5610 Computer System Architecture: Content

The document provides an overview of MIPS instruction set architecture (ISA) and its application in assembly language and machine organization. It covers essential concepts such as arithmetic operations, memory management, and control flow instructions, emphasizing the importance of registers and memory in MIPS programming. Additionally, it includes examples of translating C code to MIPS assembly and discusses the significance of pseudo-instructions for simplifying coding tasks.

Uploaded by

x6ycdqdpj6
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

Content

• Assembly Language
CSCE 5610
• Machine Language
Computer System Architecture

Machine Organization and Assembly Language

Credits of some slides go to University of Washington.

Great Idea #1: Abstraction MIPS


 In this class, we’ll use the MIPS instruction set architecture (ISA) to
illustrate concepts in assembly language and machine organization
— Of course, the concepts are not MIPS-specific
— MIPS is just convenient because it is real, yet simple (unlike x86)

 The MIPS ISA is still used in many places today. Primarily in embedded
systems, like:
— Various routers from Cisco
— Game machines like the Nintendo 64 and Sony Playstation 2
From C to Machine Language What you will need to learn soon
 You must become “fluent” in MIPS assembly:
— Translate from C to MIPS and MIPS to C

 Example problem: Write a recursive function

Here is a function pow that takes two arguments (n and m, both 32-bit
numbers) and returns nm (i.e., n raised to the mth power).

int pow(int n, int m) {


if (m == 1)
return n;
return n * pow(n, m-1);
}

Translate this into a MIPS assembly language function.

MIPS Assembly Language MIPS: Arithmetic Operations


 High-level code:
 a=b+c
 Compiled MIPS code (not actual code):

operation operands

add a, b, c

destination sources
MIPS: Register Operands Register Correspondences
 MIPS is a register-to-register, or load/store, architecture.
— The destination and sources must all be registers (Arithmetic operations).
— Special instructions, which we’ll see soon, are needed to access main memory
(memory related operations).

 MIPS processors have 32 registers, each of which holds a 32-bit value.


— Register addresses are 5 bits long. Why?
— The data inputs and outputs are 32-bits wide.

MIPS: Arithmetic Operations Basic arithmetic and logic operations


 High-level code:  The basic integer arithmetic operations include the following:
 a=b+c add sub mul div
 a, b and c in registers $t0, $t1 and $t2, respectively.  And here are a few logical operations:
 Compiled MIPS code (not actual code):
and or xor

 add $t0, $t1, $t2  Remember that these all require three register operands;
 for example:
add $t0, $t1, $t2 # $t0 = $t1 + $t2
mul $s1, $s1, $a0 # $s1 = $s1 x $a0
Larger expressions Larger expressions
 More complex arithmetic expressions may require multiple operations at  More complex arithmetic expressions may require multiple operations at
the instruction set level. the instruction set level.

t0 = (t1 + t2) × (t3 - t4) t0 = (t1 + t2) × (t3 - t4)

add $t0, $t1, $t2 # $t0 contains $t1 + $t2


sub $s0, $t3, $t4 # Temporary value $s0 = $t3 - $t4
mul $t0, $t0, $s0 # $t0 contains the final product

 Temporary registers may be necessary, since each MIPS instructions can access
only two source registers and one destination.
— In this example, we could re-use $t3 instead of introducing $s0.
— But be careful not to modify registers that are needed again later.

Immediate operands Immediate operands


 The ALU instructions we’ve seen so far expect register operands. How do  The ALU instructions we’ve seen so far expect register operands. How do
you get data into registers in the first place? you get data into registers in the first place?
— Some MIPS instructions allow you to specify a signed constant, or
“immediate” value, for the second source instead of a register. For
example, here is the immediate add instruction, addi:

addi $t0, $t1, 4 # $t0 = $t1 + 4

— Immediate operands can be used in conjunction with the $zero register to write
constants into registers:
addi $t0, $0, 4 # $t0 = 4

 MIPS is still considered a load/store architecture, because arithmetic operands


cannot be from arbitrary memory locations. They must either be registers or
constants that are embedded in the instruction.
A more complete assembly example Registers vs. Memory
 How would you write code in MIPS assembly to compute:  Registers are faster to access than memory. But it is expensive and small in size.
—1+2+3*4
 Operating on memory data requires loads and stores
 More instructions to be executed

 Compiler must use registers for variables as much as possible


 Only spill to memory for less frequently used variables
 Register optimization is important!

Memory Operands Memory review


 Main memory used for composite data.  Memory sizes are specified much like register files; here is a 2k x n RAM.
 Arrays, structures, dynamic data
2k × n memory
CS WR Operation
 So, to compute with memory-based data, you must: n
k ADRS OUT 0 x None
 Load the data from memory to the register file. n DATA
CS 1 0 Read selected address
 Do the computation, leaving the result in a register.
WR 1 1 Write selected address
 Store that value back to memory if needed.

 A chip select input CS enables or ”disables” the RAM.


 ADRS specifies the memory location to access.
 WR selects between reading from or writing to the memory.
— To read from memory, WR should be set to 0. OUT will be the n-bit value
stored at ADRS.
— To write to memory, we set WR = 1. DATA is the n-bit value to store in
memory.
MIPS memory Memory related instructions

232 × 8 memory
• Load
32 ADRS OUT
8 — Load data from memory to the registers
8 DATA
CS
WR
• Store
— Store data back to memory
 MIPS memory is byte-addressable, which means that each memory address
references an 8-bit quantity.
 The MIPS architecture can support up to 32 address lines.
— This results in a 232 x 8 RAM, which would be 4 GB of memory.
— Not all actual MIPS machines will have this much!

Loading and storing bytes Example: Loading and storing bytes


 The MIPS “load byte" instruction lb transfers one byte of data from main  C code:
memory to a register.  Char A = {‘1’,’2’,’3’,’4’}
 A[1] = A[2] + A[3]
lb $t0, 20($a0) # $t0 = Memory[$a0 + 20]
 A’s address is in $a0
 The “store byte" instruction sb transfers the lowest byte of data from a register
into main memory.  Compiled MIPS code:
sb $t0, 20($a0) # Memory[$a0 + 20] = $t0  lb $t0, 2($a0) //$t0 = A[2]
 lb $t1, 3($a0) //$t0 = A[3]
 add $t0, $t0, $t1 //$t0 = A[2] + [3]
 sb $t0, 1($a0) //A[1] = $t0
Loading and storing words An array of words
 You can also load or store 32-bit quantities—a complete word  Remember to be careful with memory addresses when accessing words.
instead of just a byte—with the lw and sw instructions.
 For instance, assume an array of words begins at address 2000.
lw $t0, 20($a0) # $t0 = Memory[$a0 + 20]
— The first array element is at address 2000.
sw $t0, 20($a0) # Memory[$a0 + 20] = $t0
— The second word is at address 2004, not 2001.

 Most programming languages support several 32-bit data types.


 Example, if $a0 contains 2000, then
— Integers
— Single-precision floating-point numbers lw $t0, 0($a0)
— Memory addresses, or pointers accesses the first word of the array, but
 Unless otherwise stated, we’ll assume words are the basic unit of lw $t0, 8($a0)
data.
would access the third word of the array, at address 2008.

Exercise Example: Loading and storing words


 Registers x Memory  C code:
 int A = {1,2,3,4}
 A[1] = A[2] + A[3]
lw $t0, 4($a0)  A’s address is in $a0

 Compiled MIPS code:


What does $a0 contain?  lw $t0, 8($a0) //$t0 = A[2]
 lw $t1, 12($a0) //$t0 = A[3]
What will $t0 contain after the instruction is executed?
 add $t0, $t0, $t1 //$t0 = A[2] + [3]
 sw $t0, 4($a0) //A[1] = $t0
MIPS: Shift Operators More Example: Loading and storing words
 MIPS contains shift operators in addition to the bit-manipulation operations.  C code:
Shift instructions move the bits to the right or left within a register.  int A
 A[1] = A[2] + A[i]
 Left shift  A’s address is in $a0, i is saved in $s0
 The shift left logical (sll) instruction has the following format:
 sll $t0, $t1, 2 //$t0 = $t1 * 22  Compiled MIPS code:
 sll by i bits multiplies by 2i  lw $t0, 8($a0) //$t0 = A[2]
 lw $t1, i?($a0) //$t0 = A[i]
 Right shift
 add $t0, $t0, $t1 //$t0 = A[2] + [3]
 The shift right logical (srl) instruction has the following format:
 sw $t0, 4($a0) //A[1] = $t0
 srl $t0, $t1, 2 //$t0 = $t1 / 22
 srl by i bits divides by 2i
 Sometimes, we can use shift operations to replace the multiplications/divisions
 It is more efficient

Computing with memory Computing with memory


 So, to compute with memory-based data, you must:  So, to compute with memory-based data, you must:
1. Load the data from memory to the register file. 1. Load the data from memory to the register file.
2. Do the computation, leaving the result in a register. 2. Do the computation, leaving the result in a register.
3. Store that value back to memory if needed. 3. Store that value back to memory if needed.

 For example, let’s say that you wanted to do the same addition, but the values  For example, let’s say that you wanted to do the same addition, but the values
were in memory. How can we do the following using MIPS assembly were in memory. How can we do the following using MIPS assembly
language? (A’s address is in $a0, result’s address is in $a1) language? (A’s address is in $a0, result’s address is in $a1)

char A[4] = {1, 2, 3, 4}; int A[4] = {1, 2, 3, 4};


int result; int result;
result = A[0] + A[1] + A[2] + A[3]; result = A[0] + A[1] + A[2] + A[3];
MIPS: Memory alignment Pseudo-instructions
 Keep in mind that memory is byte-addressable, so a 32-bit word actually  MIPS assemblers support pseudo-instructions that give the illusion of a more
occupies four contiguous locations (bytes) of main memory.
expressive instruction set, but are actually translated into one or more simpler,
Address 0 1 2 3 4 5 6 7 8 9 10 11 “real” instructions.
 For example, you can use the li and move pseudo-instructions:
8-bit data
li $a0, 2000 # Load immediate 2000 into $a0
Word 1 Word 2 Word 3 move $a1, $t0 # Copy $t0 into $a1

 They are probably clearer than their corresponding MIPS instructions:


 The MIPS architecture requires words to be aligned in memory; 32-bit
words must start at an address that is divisible by 4. addi $a0, $0, 2000 # Initialize $a0 to 2000
— 0, 4, 8 and 12 are valid word addresses. add $a1, $t0, $0 # Copy $t0 into $a1
— 1, 2, 3, 5, 6, 7, 9, 10 and 11 are not valid word addresses.
— Unaligned memory accesses result in a bus error, which you may have  We’ll see lots more pseudo-instructions this semester.
unfortunately seen before. — Unless otherwise stated, you can always use pseudo-instructions in your
assignments and on exams.
 This restriction has relatively little effect on high-level languages and
compilers, but it makes things easier and faster for the processor.

Branches and Loops MIPS control instructions: Branches


 The instructions in a program usually execute one after another, but it’s
often necessary to alter the normal control flow.  MIPS’s control-flow instructions
 Conditional statements execute only if some test expression is true.
j // for unconditional jumps
// Find the absolute value of a0 bne and beq
v0 = a0; // for conditional branches
if (v0 < 0) slt and slti // set if less than (w/o and w an immediate)
v0 = -v0; // This might not be executed
v1 = v0 + v0;
 Now we’ll talk about
 Loops cause some statements to be executed many times. — MIPS’s pseudo branches
// Sum the elements of a five-element array a0 — if/else
v0 = 0; — case/switch
t0 = 0;
while (t0 < 5) {
v0 = v0 + a0[t0]; // These statements will
t0++; // be executed five times
}
Pseudo-branches Implementing pseudo-branches
 The MIPS processor only supports two branch instructions, beq and bne, but to  Most pseudo-branches are implemented using slt. For example, a branch- if-less-
simplify your life the assembler provides the following other branches: than instruction blt $a0, $a1, Label is translated into the following.

blt $t0, $t1, L1 // Branch if $t0 < $t1


ble $t0, $t1, L2 // Branch if $t0 <= $t1 slt $at, $a0, $a1 // $at = 1 if $a0 < $a1
bne $at, $0, Label // Branch if $at != 0
bgt $t0, $t1, L3 // Branch if $t0 > $t1
bge $t0, $t1, L4 // Branch if $t0 >= $t1
 This supports immediate branches, which are also pseudo-instructions. For
example, blti $a0, 5, Label is translated into two instructions.
 There are also immediate versions of these branches, where the second
source is a constant instead of a register.
slti $at, $a0, 5 // $at = 1 if $a0 < 5
bne $at, $0, Label // Branch if $a0 < 5
 Later we’ll see how supporting just beq and bne simplifies the processor
 All of the pseudo-branches need a register to save the result of slt, even though
design.
it’s not needed afterwards.
— MIPS assemblers use register $1, or $at, for temporary storage.
— You should be careful in using $at in your own programs, as it may be
overwritten by assembler-generated code.

Translating an if-then statement Translating an if-then-else statements


 We can use branch instructions to translate if-then statements into MIPS  If there is an else clause, it is the target of the conditional branch
assembly code. — And the then clause needs a jump over the else clause
v0 = a0; move $v0 $a0 // increase the magnitude of v0 by one
if (v0 < 0) bge $v0, $0 Label if (v0 < 0) bge $v0, $0, E
v0 = -v0; sub $v0, 0, $v0 v0 --; sub $v0, $v0, 1
v1 = v0 + v0; Label: add $v1, $v0, $v0 j L
else
 Sometimes it’s easier to invert the original condition. v0 ++; E: add $v0, $v0, 1
v1 = v0; L: move $v1, $v0
— In this case, we changed “continue if v0 < 0” to “skip if v0 >= 0”.
Exercise Case/Switch Statement
 Many high-level languages support multi-way branches, e.g.
Convert the below C code snippet to MIPS assembly code. Assume variables a, b are stored
in registers t0, t1 respectively and are 32-bits non-zero positive integer. Base address of c is switch (two_bits) {
stored in register t8. Do not use multiply and divide instruction, use sll and srl instead. case 0: break;
case 1: /* fall through */
if(a > b) case 2: count ++; break;
c[a] = c[b]; case 3: count += 2; break;
else }
c[b] = c[a];
 We could just translate the code to if, thens, and elses:

if ((two_bits == 1) || (two_bits == 2)) {


count ++;
} else if (two_bits == 3) {
count += 2;
}

 This isn’t very efficient if there are many, many cases.

Case/Switch Statement Loops


Loop: j Loop # goto Loop
switch (two_bits) {
case 0: break;
case 1: /* fall through */
case 2: count ++; break;
case 3: count += 2; break;
}
for (i = 0; i < 4; i++) {
// stuff
 Alternatively, we can: }
1. Create an array of jump targets
2. Load the entry indexed by the variable two_bits
add $t0, $zero, $zero # i is initialized to 0, $t0 = 0
3. Jump to that address using the jump register, or jr, instruction Loop: // stuff
addi $t0, $t0, 1 # i ++
slti $t1, $t0, 4 # $t1 = 1 if i < 4
bne $t1, $zero, Loop # go to Loop if i < 4
Exercise Representing strings
 A C-style string is represented by an array of bytes.
Convert the below C code snippet to MIPS assembly code. Assume variables a, b are stored
in registers t0, t1, respectively and are 32-bits non-zero positive integer. Base address of c is — Elements are one-byte ASCII codes for each character.
stored in register t8. Do not use multiply and divide instruction, use sll and srl instead. — A 0 value marks the end of the array.
32 space 48 0 64 @ 80 P 96 ` 112 p
for(i=0; i<a; i++) 33 ! 49 1 65 A 81 Q 97 a 113 q
c[2*i] = c[b/4] – i; 34 ” 50 2 66 B 82 R 98 b 114 r
35 # 51 3 67 C 83 S 99 c 115 s
36 $ 52 4 68 D 84 T 100 d 116 t
37 % 53 5 69 E 85 U 101 e 117 u
38 & 54 6 70 F 86 V 102 f 118 v
39 ’ 55 7 71 G 87 W 103 g 119 w
40 ( 56 8 72 H 88 X 104 h 120 x
41 ) 57 9 73 I 89 Y 105 I 121 y
42 * 58 : 74 J 90 Z 106 j 122 z
43 + 59 ; 75 K 91 [ 107 k 123 {
44 , 60 < 76 L 92 \ 108 l 124 |
45 - 61 = 77 M 93 ] 109 m 125 }
46 . 62 > 78 N 94 ^ 110 n 126 ~
47 / 63 ? 79 O 95 _ 111 o 127 del

Null-terminated Strings What does this C code do?


 For example, “Harry Potter” can be stored as a 13-byte array.

72 97 114 114 121 32 80 111 116 116 101 114 0 int foo(char *s) {
H a r r y P o t t e r \0 int L = 0;
while (*s++) {
++L;
 Since strings can vary in length, we put a 0, or null, at the end of the string.
}
— This is called a null-terminated string
return L;
 Computing string length
}
— We’ll look at two ways.
Array Indexing Implementation of strlen Pointers & Pointer Arithmetic
int strlen(char *string) {  Many programmers have a vague understanding of pointers
int len = 0; — Looking at assembly code is useful for their comprehension.
while (string[len] != 0) {
len ++;
}
return len; int strlen(char *string) { int strlen(char *string) {
} int len = 0; int len = 0;
while (string[len] != 0) { while (*string != 0) {
len ++; string ++;
} len ++;
return len; }
} return len;
}

What is a Pointer? What is really going on here…


 A pointer is an address.
 Two pointers that point to the same thing hold the same address int strlen(char *string) {
int len = 0;
 Dereferencing a pointer means loading from the pointer’s address
 A pointer has a type; the type tells us what kind of load to do
while (*string != 0) {
— Use load byte (lb) for char *
string ++;
— Use load half (lh) for short *
len ++;
— Use load word (lw) for int * }
— Use load single precision floating point (l.s) for float *

 Pointer arithmetic is often used with pointers to arrays return len;


— Incrementing a pointer (i.e., ++) makes it point to the next element }
— The amount added to the pointer depends on the type of pointer
• pointer = pointer + sizeof(pointer’s type)
1 for char *, 4 for int *, 4 for float *, 8 for double *
Pointers Summary An Example Function: Factorial
 Pointers are just addresses!!
— “Pointees” are locations in memory int fact(int n) { fact:

li $t0, 1
int i, f = 1;
move $t1,$a0 # set i to n
 Pointer arithmetic updates the address held by the pointer for (i = n; i > 0; i--)
f = f * i;
— “string ++” points to the next element in an array return f; loop:
— Pointers are typed so address is incremented by sizeof(pointee)
} ble $t1, $0, exit # exit if done
mul $t0,$t0,$t1 # build factorial
addi $t1, $t1,-1 # i--
j loop

exit:
move $v0,$t0

Functions in MIPS Control flow in C


 We’ll talk about the 3 steps in handling function calls:
int main()
1. The program’s flow of control must be changed.  Invoking a function changes the control
{
flow of a program twice. ...
2. Arguments and return values are passed back and forth.
1. Calling the function t1 = fact(8);
3. Local variables can be allocated and destroyed. t2 = fact(3);
2. Returning from the function
 And how they are handled in MIPS: t3 = t1 + t2;
 In this example the main function calls ...
— New instructions for calling functions.
fact twice, and fact returns twice—but to }
— Conventions for sharing registers between functions. different locations in main.
— Use of a stack.  Each time fact is called, the CPU has to
remember the appropriate return address. int fact(int n)
{
 Notice that main itself is also a int i, f = 1;
function! It is called by the operating for (i = n; i > 1; i--)
system when you run the program. f = f * i;
return f;
}
Control flow in MIPS Data flow in C
 MIPS uses the jump-and-link instruction jal to call functions.
int main()
— The jal saves the return address (the address of the next instruction) in the {
dedicated register $ra, before jumping to the function. ...
— jal is the only MIPS instruction that can access the value of the program  Functions accept arguments and t1 = fact(8);
counter, so it can store the return address PC+4 in $ra. produce return values. t2 = fact(3);
 The blue parts of the program show t3 = t1 + t2;
jal Fact ...
the actual and formal arguments of the
}
fact function.
 To transfer control back to the caller, the function just has to jump to the address
 The purple parts of the code deal with int fact(int n)
that was stored in $ra.
returning and using a result. {
jr $ra int i, f = 1;
for (i = n; i > 1; i--)
 Let’s now add the jal and jr instructions that are necessary for our factorial f = f * i;
example. return f;
}

Data flow in MIPS The big problem so far


 MIPS uses the following conventions for function arguments and results.  There is a big problem here!
— Up to four function arguments can be “passed” by placing them in — The main code uses $t1 to store the result of fact(8).
argument registers $a0-$a3 before calling the function with jal. — But $t1 is also used within the fact function!
— A function can “return” up to two values by placing them in registers  The subsequent call to fact(3) will overwrite the value of fact(8) that was stored in
$v0-$v1, before returning via jr. $t1.
 These conventions are not enforced by the hardware or assembler, but
programmers agree to them so functions written by different people can interface
with each other.
 Later we’ll talk about handling additional arguments or return values.
Nested functions Spilling registers
 A similar situation happens when A: ...  The CPU has a limited number of registers for use by all functions, and it’s
you call a function that then calls # Put B’s args in $a0-$a3 possible that several functions will need the same registers.
another function. jal B # $ra = A2  We can keep important registers from being overwritten by a function call, by
A2: ... saving them before the function executes, and restoring them after the function
 Let’s say A calls B, which calls C.
completes.
— The arguments for the call to C
would be placed in $a0-$a3,  But there are two important questions.
thus overwriting the original B: ... — Who is responsible for saving registers—the caller or the callee?
arguments for B. # Put C’s args in $a0-$a3,
— Where exactly are the register contents saved?
# erasing B’s args!
— Similarly, jal C overwrites the jal C # $ra = B2
return address that was saved in B2: ...
$ra by the earlier jal B. jr $ra # Where does
# this go???

C: ...
jr $ra

Who saves the registers? The caller could save the registers…
 Who is responsible for saving important registers across function calls?  One possibility is for the caller to save
frodo: li $a0, 3
— The caller knows which registers are important to it and should be saved. any important registers that it needs li $a1, 1
— The callee knows exactly which registers it will use and potentially before making a function call, and to li $s0, 4
overwrite. restore them after. li $s1, 1
 However, in the typical “black box” programming approach, the caller and  But the caller does not know what
registers are actually written by the # Save registers
callee do not know anything about each other’s implementation. # $a0, $a1, $s0, $s1
function, so it may save more registers
— Different functions may be written by different people or companies.
than necessary.
— A function should be able to interface with any client, and different jal gollum
 In the example on the right, frodo
implementations of the same function should be substitutable.
wants to preserve $a0, $a1, $s0 and $s1 # Restore registers
 So how can two functions cooperate and share registers when they don’t know from gollum, but gollum may not even # $a0, $a1, $s0, $s1
anything about each other? use those registers.
add $v0, $a0, $a1
add $v1, $s0, $s1
jr $ra
…or the callee could save the registers… …or they could work together
 MIPS uses conventions again to split the register spilling chores.
 Another possibility is if the callee
gollum:  The caller is responsible for saving and restoring any of the following
saves and restores any registers it # Save registers caller-saved registers that it cares about.
might overwrite. # $a0 $a2 $s0 $s2
 For instance, a gollum function that $t0-$t9 $a0-$a3 $v0-$v1
uses registers $a0, $a2, $s0 and $s2 li $a0, 2
could save the original values first, li $a2, 7 In other words, the callee may freely modify these registers, under the
and restore them before returning. li $s0, 1 assumption that the caller already saved them if necessary.
li $s2, 8
 But the callee does not know what ...  The callee is responsible for saving and restoring any of the following callee-
registers are important to the caller, so saved registers that it uses. (Remember that $ra is “used” by jal.)
again it may save more registers than # Restore registers
necessary. # $a0 $a2 $s0 $s2 $s0-$s7 $ra

Thus the caller may assume these registers are not changed by the callee.
jr $ra
— $ra is tricky; it is saved by a callee who is also a caller.
 Be especially careful when writing nested functions, which act as both a caller
and a callee!

Register spilling example How to fix factorial


 This convention ensures that the caller and callee together save all of the
 In the factorial example, main (the caller) should save two registers.
important registers—frodo only needs to save registers $a0 and $a1, while
gollum only has to save registers $s0 and $s2. — $t1 must be saved before the second call to fact.
— $ra will be implicitly overwritten by the jal instructions.
frodo: li $a0, 3 gollum:  But fact (the callee) does not need to save anything. It only writes to registers
li $a1, 1 # Save registers
li $s0, 4 # $s0 and $s2
$t0, $t1 and $v0, which should have been saved by the caller.
li $s1, 1
li $a0, 2
# Save registers li $a2, 7
# $a0 and $a1 li $s0, 1
li $s2, 8
jal gollum ...

# Restore registers # Restore registers


# $a0 and $a1 # $s0 and $s2

add $v0, $a0, $a1 jr $ra


add $v1, $s0, $s1
jr $ra
Where are the registers saved? Function calls and stacks
 Notice function calls and returns occur in a
 Now we know who is responsible for saving which registers, but 1
stack-like order: the most recently called 6
we still need to discuss where those registers are saved. function is the first one to return.
A: ...
jal B
 It would be nice if each function call had its own private memory
2 A2: ...
area. 1. Someone calls A jr $ra
— This would prevent other function calls from overwriting our saved 2. A calls B 5
registers—otherwise using memory is no better than using registers. 3. B calls C
— We could use this private memory for other purposes too, like storing local 4. C returns to B B: ...
variables.
5. B returns to A jal C
6. A returns 3
B2: ...
jr $ra
4
 Here, for example, C must return to B
before B can return to A.
C: ...
jr $ra

Stacks and function calls The MIPS stack


 In MIPS machines, part of main memory is 0x7FFFFFFF
 It’s natural to use a stack for function call storage. A block of stack
reserved for a stack.
space, called a stack frame, can be allocated for each function call. stack
— The stack grows downward in terms of
— When a function is called, it creates a new frame onto the $sp
memory addresses.
stack, which will be used for local storage.
— The address of the top element of the stack
— Before the function returns, it must pop its stack frame, to
is stored (by convention) in the “stack
restore the stack to its original state.
pointer” register, $sp.
 The stack frame can be used for several purposes.
 MIPS does not provide “push” and “pop”
— Caller- and callee-save registers can be put in the stack. instructions. Instead, they must be done
— The stack frame can also hold local variables, or extra explicitly by the programmer.
arguments and return values.

0x00000000
Pushing elements Accessing and popping elements
 To push elements onto the stack: word 1
 You can access any element in the stack (not just word 1
— Move the stack pointer $sp down to $sp word 2 the top one) if you know where it is relative to word 2
make room for the new data.
$sp.
— Store the elements into the stack. $t1
 For example, to retrieve the value of $t1:
 For example, to push registers $t1 and $t2 onto $sp $t2
the stack: lw $s0, 4($sp)

sub $sp, $sp, 8 Before  You can pop, or “erase,” elements simply by
sw $t1, 4($sp) adjusting the stack pointer upwards.
sw $t2, 0($sp)
 To pop the value of $t2, yielding the stack
word 1 word 1
 An equivalent sequence is: shown at the bottom:
word 2 word 2
sw $t1, -4($sp) addi $sp, $sp, 4
sw $t2, -8($sp) $t1 $sp $t1
sub $sp, $sp, 8  Note that the popped data is still present in
$sp $t2 memory, but data past the stack pointer is $t2
 Before and after diagrams of the stack are considered invalid.
shown on the right.
After

Exercise Exercise
int pow(int n, int m) { int pow(int n, int m) {
int res = 1; if (m == 1)
for(int i = 0; i < m; i++){ return n;
res = res * n; return n * pow(n, m-1);
} }
return res;
}

pow: pow:
li $a0, 2; //n = 2 li $a0, 2; //n = 2
li $a1, 3; //m = 3 li $a1, 3; //m = 3
jal pow jal pow
Summary Next Class
 Today we focused on implementing function calls in MIPS.
— We call functions using jal, passing arguments in registers $a0-$a3.
— Functions place results in $v0-$v1 and return using jr $ra.
 Managing resources is an important part of function calls.
— To keep important data from being overwritten, registers are saved according
to conventions for caller-save and callee-save registers. Machine Language
— Each function call uses stack memory for saving registers, storing local
variables and passing extra arguments and return values.
 Assembly programmers must follow many conventions. Nothing prevents a rogue
program from overwriting registers or stack memory used by some other function.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy