CSCE 5610 Computer System Architecture: Content
CSCE 5610 Computer System Architecture: Content
• Assembly Language
CSCE 5610
• Machine Language
Computer System Architecture
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
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).
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).
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.
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 can be used in conjunction with the $zero register to write
constants into registers:
addi $t0, $0, 4 # $t0 = 4
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!
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)
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;
}
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
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!
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.