Mips Assembly Summary
Mips Assembly Summary
1000010010100000000100000
• Here we will use the MIPS CPU family to explore assembly programming
– MIPS CPU originated from research project at Stanford, most
successful and flexible CPU design of the 1990s
– MIPS CPUs were found in SGI graphics workstations, Windows CE
handhelds, CISCO routers, and Nintendo 64 video game consoles
• MIPS CPUs follow the RISC (Reduced Instruction Set Computer) design
principle:
– limited repertoire of machine instructions
– limited arithmetical complexity supported
– extensive supply of CPU registers (reduce memory accesses)
• Here: work with MIPS R2000 instruction set (use MIPS R2000 simulator
SPIM: http://www.cs.wisc.edu/~larus/spim.html)
107
• The MIPS CPU is a 32-bit architecture (all registers are 32 bits wide)
– Accessible memory range: 0x00000000–0xFFFFFFFF
MIPS: registers
8
Most of these conventions concern procedure call and return (library interoperability)
110
.data
memory:
.word 0xABCDE080 # little endian: 80E0CDAB
Register Value
$t0 0xABCDE080
$t1 0xFFFFE080
$t2 0xFFFFFF80
$t3 0x0000E080
$t4 0x00000080
112
.data
x:
.word 0x000000FF
y:
.word 0xABCDE080
113
MIPS: move
• MIPS can move data between registers directly (no memory access
involved)
Instruction Remark Pseudo?
move r, s target r , source s (r ← s) ×
# no .data segment
001100
| {z } bbbbb
| {z } bbbbb
| {z } bbbbbbbbbbbbbbbb
| {z }
andi y x c (16 bit)
115
• The MIPS standard defines the CPU instruction set as well as pseudo
instructions
9
MIPS instruction: lui r, c: load constant halfword c into upper halfword of register r
116
• Example (replace the low byte of $t0 by the low byte of $t1, leaving
$t0 otherwise intact—use bitmasks and logical instructions):
.text
.globl __start
__start:
li $t0, 0x11223344
li $t1, 0x88776655
# paste the low byte of $t1 into the low byte of $t0
# ($t0 = 0x11223355)
and $t0, $t0, 0xFFFFFF00 # pseudo
and $t1, $t1, 0xFF # assembler translates -> andi
or $t0, $t0, $t1
# no .data segment
• Question: swap the contents of register $t0 and $t1 without using
memory accesses and without using temporary registers)
.text
.globl __start
__start:
# swap values of $t0 and $t1 (xor-based)
xor $t0, $t0, $t1
xor $t1, $t0, $t1
xor $t0, $t0, $t1
# no .data segment
• Question: How could the assembler implement the rol, ror pseudo
instructions?
120
# no .data segment
121
..
again: lw $t0, memory
sub $t0, $t0, 1
beqz $t0, exit # jump offset: 2 instructions
b $t0, again # jump offset: -4 instructions
exit: sw $t1, memory
..
11
slt $at, r, s: $at ← 1 if r < s, $at ← 0 otherwise.
123
• Compare the values of two registers (or one register and a constant)
successful: r ← 1
– Comparison
fails: r ←0
Instruction Comparison Remark Pseudo? MIPS instructions
slt r, s, t s <t
sltu r, s, t s<t unsigned
slti r, s, c s<c c 16-bit constant
sltiu r, s, c s <c unsigned
seq r, s, t s=t × beq s, t, 3
ori r, $zero, 0
beq $zero, $zero, 2
ori r, $zero, 1
sne r, s, t s 6 t
= ×
sge r, s, t s >t ×
sgeu r, s, t s >t unsigned ×
sgt r, s, t s >t ×
sgtu r, s, t s >t unsigned ×
sle r, s, t s 6t ×
sleu r, s, t s 6t unsigned ×
124
12
Leonardo Fibonacci (Leonardo di Pisa), 1200
126
.data
result: .word 0x11111111
127
R←0
A−1 ← 0
i ←n
– Register assignment:
Register Usage
= 10
A0, A−1
= 01
$a0 A
= 00 $a1 C
= 11 $v0 R
R ← R−C R ←R+C
$t0 i
$t1 A−1 (only bit 0 of $t1 used)
ASR R, A, A−1 – Implementation quite straightforward, ASR
i ←i −1
of “connected registers” R, A, A−1 needs
No
i = 0? some care
Yes
END
128
la $t0, str
lb $t1, ($t0) # access byte at address $t0 (’f’)
add $t0, $t0, 3
lb $t2, ($t0) # access byte at address $t0 + 3 (’b’)
.data
• Note the difference between
• Actually, in keeping with the RISC philosophy, MIPS has only one general
memory addressing mode: indexed addressing
– In indexed addressing, addresses are of the form (16-bit constant c,
CPU register r )
c(r )
r holds a 32-bit address to which the signed 16-bit constant c is
added to form the final address
Example (repeated from last slide):
.text
la $t0, str
lb $t1, 0($t0) # access byte at address $t0 (’f’)
lb $t2, 3($t0) # access byte at address $t0 + 3 (’b’)
.data
.data
Remarks:
– Place system call code in $v0, then execute syscall
– System call read integer reads an entire line (including newline) and
ignores characters following the number
– The read string system call reads at most $a1 − 1 characters into the
buffer and terminates the input with a null byte
137
li $v0, 10 # exit
syscall
.data
the_result_is:
.asciiz "The result is "
138
Bubble sort
• Basic idea:
1 j ← n − 1 (index of last element in A)
2 If A[j] < A[j − 1], swap both elements
3 j ← j − 1, goto
2 if j > 0
4 Goto
1 if a swap occurred
140
Procedures (sub-routines)
– Instead of copying and repeating the procedure code over and over,
1 the main program calls the procedure
(jumps to the procedure code),
2 the called procedure does its job before it returns control
(jumps back to the instruction just after the procedure call)
– The main program is often referred to as the caller, the procedure as
the callee
143
.
.
li $a0, $t0 # set parameter x
li $a1, 12 # set parameter y
j average # compute average
F1: move $t0, $v0 # save result
.
.
.
.
li $a0, $t0 # set parameter x
li $a1, $t1 # set parameter y
j average # compute average
F2: move $t1, $v0 # save result
.
.
• After the first call, average needs to return to label F1, after the second
call the correct address to return to is F2
145
• MIPS instruction jal (jump and link) jumps to the given address a
(procedure entry point) and records the correct return address in
register $ra:
Instruction Effect
jal a $ra ← IP + 4
IP ← a
• The callee may then simply return to the correct address in the caller via
Instruction Effect
j $ra IP ← $ra
– $ra is reserved MIPS CPU register $31; programs overwriting/abusing
$ra are likely to yield chaos
146
.
.
.
li $a0, $t0 # set parameter x
li $a1, 12 # set parameter y
jal average # compute average ($ra = F1)
F1: move $t0, $v0 # save result
.
.
.
li $a0, $t0 # set parameter x
li $a1, $t1 # set parameter y
jal average # compute average ($ra = F2)
F2: move $t1, $v0 # save result
.
.
.
li $v0, 10 # exit program
syscall
Recursive algorithms/procedures
1 Is the size of the problem such that we can trivially solve it?
Yes ⇒ Return the answer immediately
2 Try to reduce the size/complexity of the original problem
3 Invoke the algorithm on the reduced problem
• In step
3 , the algorithm invokes itself to compute the answer; such
algorithms are known as recursive
Binary search
• General idea:
1 If the array is of size 1 only, compare needle against the array entry,
return result of comparison (true/false)
2 Locate the middle array entry m; compare needle and m
3 – If needle = m return true
– If needle < m, call binary search on left half of array
– Otherwise, call binary search on right half of array
• NB: since the array is sorted, we know for all entries a to the left of m
that a 6 m (for all entries b to the right of m: b > m)
149
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
2 2 3 8 10 16 21 35 42 43 50
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
3 2 3 8 10 16 21 35 42 43 50
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
2 2 3 8 10 16 21 35 42 43 50
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
3 2 3 8 10 16 21 35 42 43 50
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
2 2 3 8 10 16 21 35 42 43 50
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
3 2 3 8 10 16 21 35 42 43 50
150
• Binary search is very efficient: in each recursive call, the size of the
problem is cut in half
– Let the original array come with n entries; each recursive call halves the
problem size:
1 1 1
n · · · ···
2 2 2
– Binary search is guaranteed to end after s recursive calls when the array
size has been reduced to 1:
s
1 ! n
n· =1 ⇔ s
= 1 ⇔ s = log2 n
2 2
array size n dlog2 ne
10 4
100 7
1000 10
10000 14
100000 17
1000000 20
151
• Note that the MIPS procedure call/return via jal a/j $ra does not
work for recursive procedures
# procedure
proc: .
.
jal proc # recursive call ($ra = F2)
F2: .
.
j $ra # (will jump to F2, not F1)
152
# procedure
proc: save $ra
.
.
jal proc # recursive call ($ra = F2)
F2: .
.
restore $ra
j $ra # will jump to F1
NB: Each invocation of proc needs its own place to save
$ra—the save location will otherwise be overwritten in the recursive call!
153
1 .data
2
3 first: # sorted array of 32 bit words
4 .word 2, 3, 8, 10, 16, 21, 35, 42, 43, 50, 64, 69
5 .word 70, 77, 82, 83, 84, 90, 96, 99, 100, 105, 111, 120
6 last: # address just after sorted array
7
8 .text
9 .globl __start
10 __start:
11
12 # binary search in sorted array
13 # input: search value (needle) in $a0
14 # base address of array in $a1
15 # last address of array in $a2
16 # output: address of needle in $v0 if found,
17 # 0 in $v0 otherwise
18 li $a0, 42 # needle value
19 la $a1, first # address of first array entry
20 la $a2, last - 4 # address of last array entry
21 jal binsearch # perform binary search
22
23 li $v0, 10
24 syscall
25
158